2026-09-21. The Unity work is complete at implementation commit a7fff23.
This record supersedes the open-ended sequencing and stale checklist in
the original research plan, which remains the source
of the ASR comparison and implementation evidence.
Ship the researched ASR profiles and runtime improvements, plus the requested recursive String/array/List/Map/Set reads and owned class snapshots. Unused features must not add their discovery/readers to Wasm. Lunistice Release finishes at 32,121 bytes with an explicit profile and 142,234 bytes with automatic selection, preserving the existing source, output pipeline, and base/DLC behavior. The user accepted stopping when no further concrete optimization saves roughly 500 bytes or more; this replaces the earlier below-30,000-byte completion gate. Breaking internal changes are fine.
Do not add further features or expand malformed-metadata coverage without a concrete defect that prevents these requirements from working. Raw UTF-16, migration support, and unrelated compiler optimization are outside this work.
These are stored measurements, inspected without rebuilding:
| Revision | Explicit Lunistice bytes | Change |
|---|---|---|
001c38a |
23,141 | Before IL2CPP profile migration |
52f5b65 |
76,166 | Profile migration and source-defined metadata discovery |
d5cc416 |
74,926 | Nested-name/generic metadata changes |
8590627 |
56,641 | Shared field traversal |
8a759ae |
60,345 | Implementation at the start of this audit |
| Before class-scan change | 57,399 | Pending discovery consolidation |
57ed738 |
49,437 | Bounded synchronous class scan |
7545e6f |
43,627 | Bounded image scan and fixed-width discovery |
c4b0e39 |
41,504 | Debug-only descriptor sanity checks |
c5089e5 |
40,194 | Direct field binding |
2c0dc00 |
38,995 | Smaller lookup continuations |
36c30ef |
36,922 | Remove unused linear-memory string copies |
c46a76e |
36,136 | Unqualified schema class matching |
4473e70 |
34,436 | Passive GC string initializers |
eedc9ff |
33,234 | Grouped required-field binding |
bb9485a |
32,353 | Name-only lookup diagnostics |
a7fff23 |
32,121 | Shared required/conditional binding; final retained implementation |
Historical evidence: tests/baselines/unity.json at each revision. The tracked
baseline at a7fff23 records the final accepted measurements.
The major regression happened during the profile migration, before the nested
collection work. At 52f5b65, field lookup alone occupied 21,166 bytes and class
lookup 14,611 bytes. The migration replaced compact compiler-generated readers
with source-defined async discovery. The generated implementation, rather than
just the number of profile entries, made this expensive.
At the start of this audit, explicit output contained 50,604 bytes of code, 2,838 bytes of data, and 3,957 bytes of other sections/framing. Its largest function bodies included:
| Function | Bytes |
|---|---|
| Class discovery poll | 9,750 |
| Selected provider preparation poll | 4,453 |
| Image discovery poll | 3,173 |
| IL2CPP global discovery poll | 2,292 |
| Shared field traversal step | 2,284 |
| Profile validation | 1,941 |
| Shared field traversal poll | 1,622 |
These were absolute costs, not individually proven removable savings. They did not attribute every byte of growth. That output also retained a 1,020-byte 32-bit table-discovery poll despite selecting a fixed x64 profile. This and runtime validation of a built-in constant profile became specialization targets, addressed in the historical checkpoints below.
The old IL2CPP year/version API is already removed. Mono's V1/V1Cattrs/V2/V3 families remain in current ASR, and no Mono functions appear in the explicit Lunistice report. That report contains the selected profile factory and no automatic profile-selection catalog. Removing legacy version tables is therefore not a pending fix for this artifact.
The finite audit below maps all 14 researched ASR PRs and the additional nested managed-value/snapshot requirements to implementations and fixtures. No requested feature remains missing. Imported profiles, unused-feature exclusion, recursive reads, snapshot failure behavior, and Lunistice editions have passed verification. The final retained source passes 690 compiler tests, 210 public runtime scenarios across 172 validated artifacts, documentation validation, formatting, and Clippy. The private adapter checks and their resource-limited execution are recorded below.
The final size remains above the original target. A subsequent width-reader experiment saved only 109 bytes; another candidate shared a 321-byte scan body. Both experiments were discarded under the user's stopping criterion. There is no demonstrated remaining saving above roughly 500 bytes to pursue within this scope. General Release compiler optimization and explicit field/property syntax remain separate TODO items, not completion dependencies.
All builds/tests use the serialized scripts/run_limited.py resource guard.
No game was launched for closeout. Native Linux/macOS live-game validation remains
unavailable; platform fixtures and Lunistice's live title-screen attachment are
not claims of full live playthrough validation.
The sections below retain the investigation history. Their intermediate size targets and “Remaining” notes describe those checkpoints, not current blockers.
IL2CPP class lookup now performs at most 64 slots in a synchronous step, with a small async wrapper retaining only the scan cursor. Failed batches retry without committing partial progress. Null slots, delayed initialization, ambiguity, negative starts, count limits, nested matching, yielding, and cancellation retain their existing behavior. This follows the existing field cursor approach.
The isolated change reduces explicit Lunistice from 57,399 to 49,437 bytes (-7,962), and automatic selection from 179,728 to 171,009 bytes (-8,719). The class step is 1,140 bytes; the former class poll was 9,750 bytes. Combined with the previously pending checked-name/image consolidation, explicit output shrinks 10,908 bytes relative to the committed baseline. It is still 19,438 bytes above the maximum permitted by the below-30,000-byte requirement.
All 33 metadata artifacts validate and all 38 associated runtime scenarios pass, including 98 bounds/retry cases in each build profile, profile selection, nested names, inherited fields, and cancellation. Both Lunistice editions pass. All 38 baseline artifacts shrink or remain the same size; native, local Map/Set, and standalone identity/export fixtures retain identical sizes. Runtime helper sets, scratch requirements, and initial memory pages are unchanged. The small increases in function/type counts represent the cursor, its result, and synchronous helpers replacing the much larger async routine; they do not reverse the byte savings.
The 48 compiler profile/code-generation tests and documentation validation also pass under the resource guard.
The next size work remains discovery/preparation and specialization of known profile facts. This change does not establish final parity or final size acceptance.
IL2CPP image discovery now scans at most 64 assembly slots synchronously and keeps a small async continuation. A failed batch retries without losing earlier completed batches. The fixtures cover large vectors and repair in a later batch at both pointer widths, in addition to the existing initialization/error cases.
Generated state preparation selects the matching discovery root when a literal profile or zero-argument constructor chain exposes its pointer width. Built-in profiles and ordinary custom descriptors use this path. More complex constant expressions conservatively retain generic discovery. Profile and target-width validation still run. Automatic selection and ordinary dynamic calls continue to support both architectures. This is a bounded specialization in existing Unity provider preparation, not a general compiler optimization pass.
Explicit Lunistice shrinks 49,437 -> 43,627 bytes (-5,810), with both editions passing. Its x86 discovery functions are absent. The x86 fixture likewise omits the x64 discovery routine and relative-target scan helper. Automatic Lunistice shrinks 171,009 -> 170,339 bytes (-670). Automatic output retains separate architecture routines and their types; the image-scan savings exceed that cost. Every one of the 38 baseline sources is unchanged, no fixture grows, and no new runtime helper, scratch capacity, or initial memory page is retained.
All 49 profile/code-generation tests pass, including built-in x86/x64 profiles, constructor aliases, custom descriptors, and opposite-architecture exclusion. All 33 metadata artifacts validate and all 38 runtime scenarios pass. The bounds fixture now has 102 cases per build profile with a maximum of 259 reads in one update, including the new image-batch retry cases.
The 56 catalog/type-checking tests, Clippy with warnings denied, and documentation validation also pass under the resource guard.
The explicit artifact remains 13,628 bytes above the largest size permitted by the completion requirement. The original parity audit and final size acceptance remain open; this checkpoint does not add another feature requirement.
Following the user's request, IL2CPP descriptor alignment, offset, and stride
sanity checks now use the existing debug statement. Debug still rejects the
malformed custom-profile fixture before discovery. Release omits the validator
for both measured and custom profiles. Target pointer-width validation remains
in both build profiles, as do checked reads, bounded traversal, and snapshot
failure behavior. No separate trusted-profile API or compiler routing was added.
Explicit Lunistice shrinks 43,627 -> 41,504 bytes (-2,123), with both editions passing. Automatic selection remains 170,339 bytes. All 38 size fixtures shrink or stay unchanged; runtime helper sets, scratch capacity, and memory pages are unchanged. The 49 profile/code-generation tests pass, including Debug retention and Release exclusion of descriptor validation. All five relevant runtime artifacts validate and pass 56 cases, covering measured profiles, custom profiles, wrong target widths, reattachment, and malformed descriptors in Debug. Documentation validation passes. Builds and tests ran through the resource guard.
Final size acceptance remains open: 11,505 bytes must still be removed to reach an artifact strictly below 30,000 bytes. The parity audit also remains open.
The review uses ASR commit cf732d3aeac7509c8ab5f29a4d0d28f16487d245 in a
separate local checkout; the user's ASR branch and changes remain untouched.
Both profile importers pass --check against that commit: 26 PE Mono profiles
and eight fallbacks, 13 ELF profiles and four fallbacks, two Mach-O profiles and
four fallbacks, and 22 complete IL2CPP profiles. These checks compare the source
library and checked-in fixture catalogs, not just profile counts.
| Requirement | Current implementation | Maintained behavior evidence |
|---|---|---|
| #142 binary identities and testing | Module.peDebugId, elfBuildId, machUuid; synthetic host and mapped-image fixtures |
pe_debug_id_runtime.mjs, unix_identity_runtime.mjs |
| #143 Windows Mono profiles | Imported GUID+age/width descriptors, old and modern module discovery, assembly/image name routes | mono_profiles_runtime.mjs |
| #144 IL2CPP layouts and discovery | Full descriptors, x86/x64 scans, inline/handle starts, bounded module windows | il2cpp_profiles_runtime.mjs, unity_metadata_bounds_runtime.mjs; intermediate version selection superseded by #160 |
| #145 shared traversal | UnityClassNames, UnityFields, backend cursors, declaring-owner propagation |
unity_field_cursor_runtime.mjs, mono_metadata_cursor_runtime.mjs, unity_metadata_bounds_runtime.mjs |
| #146 nested/generic metadata and statics | Declaring-chain names, Mono generic-definition counts, IL2CPP sentinel count, owner-relative statics | unity_nested_metadata_runtime.mjs, mono_generic_metadata_runtime.mjs, managed_inherited_static_runtime.mjs, mono_static_path_runtime.mjs |
| #147 managed strings and value arrays | Width-aware object headers, stored lengths, shared managed decoder graph | managed_string_width_runtime.mjs, managed_arrays_runtime.mjs; raw UTF-16 intentionally excluded |
| #148 lists | Runtime ancestor/layout discovery, actual size versus backing capacity, attachment-scoped cache | managed_list_layout_runtime.mjs, managed_lists_runtime.mjs |
| #150 dictionaries | Validated entry metadata and live-slot scan, recursive local Map construction |
managed_keyed_layout_runtime.mjs, managed_keyed_slots_runtime.mjs, managed_maps_runtime.mjs |
| #151 hash sets | Slot layout/high-water scan and recursive local Set construction |
The shared keyed fixtures plus managed_sets_runtime.mjs |
| #152 old corlib parallel arrays | Separate links/keys/values or slots, either link-member order, hash-high-bit liveness | Parallel modes in the keyed, map, and set fixtures |
| #153 reference arrays/lists and direct strings | Pointer-width element slots, nullable children, recursive string/object decoders | Array/list/string fixtures and managed_deep_snapshot_runtime.mjs |
| #155 Linux Mono | Runtime-ID precedence, measured/fallback layouts, ELF symbol and x64 discovery | mono_linux_runtime.mjs, mono_explicit_unix_runtime.mjs, elf_export_runtime.mjs |
| #156 macOS Mono | Active-slice UUID/architecture, x86_64 and ARM64 discovery, measured/fallback layouts | mono_mac_runtime.mjs, mono_explicit_unix_runtime.mjs, mach_export_runtime.mjs |
| #160 final IL2CPP selection | Complete explicit/custom profiles; exact four-part version then major/minor fallback; removed year selectors | Profile importer, il2cpp_profiles_runtime.mjs, compiler profiles_codegen tests |
The internal list/keyed layout and IL2CPP storage fixtures run through
src/managed_collection_layout_tests.rs; public schema fixtures run through
the xtask runtime catalog. Both must be included in final verification.
Beyond ASR, src/managed_read.rs models fixed memory values, strings, arrays,
lists, maps, sets, classes, and nullable children as composable decoder nodes.
Compiler capability tests cover the MemoryReadable implication and generic
constraints. Public fixtures exercise maps of string arrays, arrays of maps,
nested keyed collections, lists of class snapshots, recursive class trees,
nullability, duplicate decoded keys, and transitive freezing. They also check
that a failed nested read preserves current and old. The compiler's unused
schema tests compare actual module/section sizes, helpers, data bounds, and
scratch requirements, rather than relying only on retained symbol names.
The runtime and Lunistice port transparently recognize property backing fields,
as ASR does. Conflicting exact-name documentation and an AST comment have been
corrected to describe that behavior. The user prefers explicit field/property
intent in the future; the syntax decision is deferred in TODO.md. The
experimental exact-name change and its Lunistice source edits were reverted.
A stale standard-library paragraph also claimed IL2CPP generic storage was unimplemented; it now describes the existing implementation.
No additional requested feature is identified by this review. Final verification
and size acceptance are recorded in the completion status above. Native Linux/macOS
game validation is unavailable here and remains explicitly unverified; the
platform evidence above is synthetic. Lunistice's recorded live evidence covers
title-screen attachment, while maintained fixtures cover base/DLC behavior.
The separate P1 compiler optimization project in TODO.md is not a dependency.
Removed redundant IL2CPP forwarding futures and the obsolete !0 ambiguity
sentinel check: the shared field cursor already rejects ambiguous metadata.
Checks, rejection messages, backing-field matching, retry, cancellation, and
declaring-owner static storage remain in place. Lunistice source is unchanged.
Explicit Release shrinks 41,504 -> 40,194 bytes (-1,310); automatic selection
shrinks 170,339 -> 168,934 bytes (-1,405). All 38 baseline artifacts shrink or
stay unchanged, with the same source fingerprints, runtime helpers, scratch
capacities, and initial page counts. The 33 metadata artifacts and 38 associated
runtime scenarios passed for this isolated change, as did both Release
Lunistice editions. Evidence is in target/unity-direct-fields-*.log.
The retained wrapper-only patch was rebuilt and the 33-artifact / 38-scenario
metadata matrix passed again. All 38 baseline sources are unchanged, both
Release Lunistice editions pass, and the reviewed baseline passes its strict
gate. Final evidence is in target/unity-direct-fields-final-*.log.
The broader exact-alias experimental test run is not used as verification of
this retained patch. General compiler optimizations remain deferred.
Remaining: remove another 10,195 bytes to get strictly below 30,000, then run the final repository checks. The finite functional audit found no further missing requested features. No game was launched.
Moved field-name expansion into a synchronous helper, removed the image lookup forwarding future, and merged required-class validation into the class scan continuation. Static-slot lookup retries its table read and checked offset together. Matching, ambiguity, missing-class behavior, and cancellation are preserved. These are library changes to the discovery routines introduced by the Unity migration; general compiler optimizations remain deferred.
Explicit Lunistice shrinks 40,194 -> 38,995 bytes (-1,199); automatic selection shrinks 168,934 -> 167,631 bytes (-1,303). All 38 baseline artifacts shrink or stay unchanged, with identical runtime helper sets, scratch capacities, read capacities, and initial page counts. The static-slot retry adds a 36-byte error literal while removing substantially more continuation code and types. Nine unaffected artifacts retain identical normalized function bodies and sections. The Lunistice source fingerprint changes only because of a line wrap; compiling the prior source with the current compiler produces byte-identical Release Wasm.
All 33 metadata artifacts and 38 runtime scenarios pass, both Release Lunistice
editions pass, and documentation validation passes. Logs are
target/unity-lookup-continuations-*.log.
Remaining: remove another 8,996 bytes to get strictly below 30,000, then complete final repository verification. No game was launched.
The static-data planner interned every reachable string expression, although ordinary strings are constructed as GC arrays. This also retained text from Unity metadata errors whose payload construction was already omitted. Static strings now follow their actual ABI consumers: process and module names, settings, pointer paths, and attachment-shape reports. GC string construction, error behavior, signature data, and the output pipeline are unchanged. This fixes demand-driven emission; it does not introduce the deferred general optimization passes or the earlier string-pooling experiment.
Explicit Lunistice shrinks 38,995 -> 36,922 bytes (-2,073); automatic selection shrinks 167,631 -> 159,829 bytes (-7,802). All 38 artifacts shrink or remain unchanged. Source fingerprints, function-body byte counts, type/function counts, helper sets, scratch capacity, and initial pages are identical. Both Release Lunistice editions pass.
Reachability tests now inspect GC byte-array instructions as well as literal bytes. New checks cover retained module-query data, omitted GC/error copies, and large strings that do or do not require linear memory. The compiler run passed 684 tests; its sole failure was an outdated page-count expectation in the new settings case. After correcting that expectation, all 50 profile tests and the targeted signature-data test pass.
The full public runtime catalog compiled and validated 170 artifacts and passed
207 of 208 scenarios. The remaining smoke fixture supplied a GameManager object
without its IL2CPP class header, so the existing nominal-class check rejected it.
Adding the missing header makes that scenario pass as well. No runtime behavior
was changed to accommodate the fixture. Logs: target/unity-static-data-*.log.
The strict regression baseline, documentation validation, Rustfmt, and Clippy with warnings denied pass under the resource guard.
Remaining: remove another 6,923 bytes to get strictly below 30,000, then complete final repository verification. No game was launched.
Generated binding selects a simple comparison when every candidate for that class lacks namespace and declaring-class qualifiers. Qualified aliases and namespace declarations keep the flat matcher; nested names keep declaring-chain matching. The decision is per class, so an unused qualified declaration cannot force a parser into an otherwise simple script. Runtime ambiguity checks and unqualified names' namespace-agnostic meaning are preserved.
Explicit Lunistice shrinks 36,922 -> 36,136 bytes (-786); automatic selection
shrinks 159,829 -> 158,930 bytes (-899). Explicit output no longer retains
StringRFind or StringSlice for class matching. None of the 38 baseline
artifacts grows; source fingerprints, scratch/read capacities, and initial page
counts are unchanged, and no new runtime helper is retained.
All 50 profile/code-generation tests pass, including qualified, mixed-alias,
namespace, nested, and unused-declaration cases. All 33 metadata artifacts and
38 runtime scenarios pass. The bounds fixture now has 108 cases per build
profile, including unqualified names in nonempty runtime namespaces at both
pointer widths. Both Release Lunistice editions, documentation, Rustfmt, and
Clippy with warnings denied pass. Logs: target/unity-unqualified-*.log.
Remaining: remove another 6,137 bytes to get strictly below 30,000, then complete final repository verification. No game was launched.
Release emits GC string literals of at least 32 UTF-8 bytes with array.new_data
instead of one constant instruction per byte. One passive segment stores the
initializer bytes, deduplicating identical text while preserving separate GC
allocations. Bytes are collected only when a constructor is actually emitted;
discarded error payloads and unreachable functions retain no initializer data.
This directly reduces the diagnostic-string overhead introduced by source-defined
Unity discovery. General compiler optimization passes remain deferred.
Explicit Lunistice shrinks 36,136 -> 34,436 bytes (-1,700); automatic selection shrinks 158,930 -> 147,572 bytes (-11,358). The explicit artifact removes 2,553 code bytes and adds 853 bytes of passive data and section metadata. None of the 38 baseline artifacts grows. Source fingerprints, type/function counts, helper sets, scratch/read capacities, and initial pages are unchanged. Passive bytes occupy no linear memory. Debug encoding remains unchanged: the checked IL2CPP fixture is byte-identical excluding compiler-identity metadata.
All 687 compiler tests pass, including demand-driven initializer retention and
Unicode allocation across suspensions. The full public runtime catalog validates
170 artifacts and passes 208 scenarios; both Release Lunistice editions pass.
Documentation validation (561 pages) and Clippy with warnings denied pass.
Evidence: target/unity-passive-strings-*.log.
Remaining: remove another 4,437 bytes to get strictly below 30,000, then complete final repository verification. No game was launched.
The reviewed 38-artifact baseline passes its strict comparison, including both
Release Lunistice editions (target/unity-passive-strings-baseline-strict.log).
Both profile importers also pass --check against the pinned ASR audit checkout
(target/unity-final-mono-profiles.log, target/unity-final-il2cpp-profiles.log).
The seven private adapter tests in src/managed_collection_layout_tests.rs
still need a fresh run. Building the full library-test executable exceeded the
1,536 MiB hard process-tree cap with native optimization levels 3, 1, and 0.
These are build-resource failures, not executed test failures. The cap remains
unchanged. Logs: target/unity-final-private-build*.log. The successful public
compiler/runtime results above do not substitute for these private fixtures.
An experiment replacing metadata-name debug arrays with joined strings was
reverted: explicit Lunistice grew by 43 bytes and retained the same helpers.
Its build and report (target/unity-name-diagnostics-*) are not evidence for
the retained source. In particular, target/release binaries and the ephemeral
target/unity-baseline/report.json from that experiment need rebuilding before
further measurements; the checked-in baseline records the accepted 34,436 bytes.
Inspection identified a specific follow-up: codegen/dependencies.rs retains
all structural debug helpers whenever any structural debug formatter is used.
Determine the actual formatter requirements before changing that dependency
rule. No prospective saving is counted. Default async-frame construction was
also investigated but left unchanged because the immutable dispatch tag
prevents a direct struct.new_default substitution.
All seven groups from src/managed_collection_layout_tests.rs now pass against
the retained compiler source at 460eb35. To avoid compiling unrelated library
unit tests, a temporary Cargo example used a copy of the production crate root
plus the existing fixture module, removing only its #[test] attributes and
calling the seven functions sequentially. No assertions, input fixtures, Node
harnesses, or production behavior were changed. The temporary example entry and
source were removed after execution.
The guarded build passed at 1,473 MiB peak and execution at 634 MiB. Both Wasm
profiles cover collection type contracts, list layouts, keyed layouts/slots,
Mono declaring-owner static paths, and IL2CPP plain/generic storage. The latter
two run 462 and 330 cases respectively in each profile. Evidence:
target/unity-private-runner-build.log, target/unity-private-runner-runtime.log.
This closes the private-fixture gap above without raising the memory cap.
The first field-grouping prototype was removed before compilation: grouping lookups before managed demand pruning would retain unused field lookups. Any future grouping must be selected only after actual field demand is known and preserve the individual-lookup path for partially used schemas. No source or size change from that prototype is retained. The accepted size remains 34,436.
Classes with at least four demanded required fields share one async binding loop. The existing managed-demand pass selects and compacts the group's input names/static flags and remaps its result slots before lowering. Smaller groups keep individual lookups. Adding an unused field cannot retain its discovery or disable grouping for the fields that are used. Conditional fields keep their existing completed-absence handling. Declaration order, retries, cancellation, and inherited static storage owners are preserved on both backends and through automatic selection. Lunistice source and diagnostic text are unchanged.
The new loops exposed an existing type leak: range layouts were emitted even when unreachable. Range layouts now follow the same reachability requirement as other GC types. This removes the prototype's native-only size increase; the native fixture shrinks from 615 to 597 bytes. No general optimization pass was introduced.
Explicit Lunistice shrinks 34,436 -> 33,234 bytes (-1,202); automatic selection shrinks 147,572 -> 145,268 bytes (-2,304). Preparation's poll body shrinks from 4,453 to 3,167 bytes. None of the 38 baseline artifacts grows; their source fingerprints, runtime helper sets, scratch/read capacities, linear static data, and initial page counts are unchanged. The final subset-compaction refinement leaves all 38 artifact sizes, sections, function bodies, and emission reports identical to the first version with range pruning.
All 689 compiler tests passed before the final subset-compaction refinement. After refinement, all 53 profile/code-generation tests pass, including scalar unused-field exclusion, grouped reads with an unused nested Map, and unused range exclusion. For the Map case, existing GC type indices can reorder without changing size or retaining additional functions/helpers; requiring identical type numbering would exceed the demand-driven guarantee being tested.
Evidence: target/unity-binding-batch-compiler.log,
target/unity-binding-batch-subset-profiles.log, and
target/unity-binding-batch-subset-baseline.log.
The final public runtime run validates 172 artifacts and passes all 210
scenarios. The grouped cursor fixture adds 28 cases in each build profile,
covering both pointer widths/backends, inherited static owners, ambiguity,
bounded traversal, and repair after a later field's metadata fails. An unused
nested Map field is deliberately absent from the simulated game. Both Release
Lunistice editions pass. Documentation validation (561 pages), Rustfmt, and
Clippy with warnings denied pass. Logs:
target/unity-binding-batch-subset-runtime.log,
target/unity-binding-batch-docs.log, target/unity-binding-batch-clippy.log.
Remaining: remove another 3,235 bytes to get strictly below 30,000, then complete the final size acceptance. No game was launched.
Unity's seven class/field lookup diagnostics now join candidate names directly. They retain the failure reason and names without invoking structural array formatting. The shared field cursor's error branch must use the same formatting: changing only the outer lookup messages leaves the array formatter reachable. No lookup, alias expansion, suspension, or Lunistice source behavior changes.
Explicit Lunistice shrinks 33,234 -> 32,353 bytes (-881); automatic selection
shrinks 145,268 -> 144,418 bytes (-850). Five functions disappear: the array
formatter and QuoteDebugString, IndentDisplay, WrapDebugEntry, and
WrapDebugVariant. None of the 38 baseline artifacts grows; their sources,
scratch/read capacities, linear static data, and initial page counts are
unchanged. Native and non-Unity fixtures are unchanged in size.
All 172 public runtime artifacts validate and all 210 scenarios pass. Field
cursor rejection cases now assert that the same message contains both aliases
and the failure reason, across both backends and widths, in both build profiles.
Both Release Lunistice editions, the reviewed baseline gate, and documentation
validation pass. Evidence: target/unity-name-diagnostics-runtime.log,
target/unity-name-diagnostics-strict.log, and
target/unity-name-diagnostics-docs.log. All builds and tests ran serially under
the existing memory limits. No game was launched.
Remaining: remove another 2,354 bytes to get strictly below 30,000, then complete final size acceptance. Directly returning a child future from a synchronous forwarding function is not currently supported; do not turn that into a general compiler optimization project as part of this migration.
The existing demand-selected binding loop now includes conditional fields. Its result separates final offsets/static addresses from original field metadata, so required fields read their values directly and conditional fields retain completed absence. Required absence still rejects attachment; unreadable metadata still retries. Inherited static storage uses the declaring owner. No partial group becomes visible to state reads. Small demanded groups retain their individual lookup paths, and unused required or conditional fields are removed before grouping and result-slot assignment.
Explicit Lunistice shrinks 32,353 -> 32,121 bytes (-232); automatic selection shrinks 144,418 -> 142,234 bytes (-2,184). The explicit preparation poll shrinks from 3,166 to 2,904 bytes. The other 36 measured artifacts are unchanged in size. All 38 preserve their source fingerprints, runtime helper sets, scratch/read capacities, linear static data, and initial page counts.
All 54 profile/code-generation tests pass, including unused nested Maps inside
conditional groups. All 172 public runtime artifacts validate and all 210
scenarios pass. The grouped fixture runs 36 cases per build profile across both
backends and widths, including optional absence, required absence, late metadata,
inherited owners, and bounded traversal. Both Release Lunistice editions,
the reviewed baseline gate, documentation validation (561 pages), and Clippy
with warnings denied pass. Evidence: target/unity-optional-batch-slots-profiles.log,
target/unity-optional-batch-slots-runtime.log,
target/unity-optional-batch-slots-strict.log,
target/unity-optional-batch-slots-docs.log, and
target/unity-optional-batch-slots-clippy.log.
The full compiler suite also passes all 690 tests against this final source
(target/unity-optional-batch-slots-compiler.log); Rustfmt passes. Every command
used the existing serialized memory guard, without raising its limits.
Complete: retained at a7fff23 under the user's roughly-500-byte stopping
criterion. Explicit output is 32,121 bytes; automatic output is 142,234 bytes.
No requested feature remains outstanding. No game was launched.
After discarding the two small experiments, the restored implementation was
rebuilt under the unchanged memory cap. The fresh baseline matches all 38
accepted artifact sizes and passes Lunistice base/DLC behavior; documentation
validation also passes. Evidence: target/unity-closeout-build.log,
target/unity-closeout-baseline.log, and target/unity-closeout-docs.log.