# Chapter backport queue This file tracks pending backports and deferred work. Completed work and old validation results belong in Git history. Reusable implementation constraints live in the [AI notes](../skills/chapter25-codex-notes.md). The [completed split](chapter-split.md) places local/interprocedural SCCP in 24a/24b, incomplete types in 25, construction in 26, escape in 27, and modules/separate compilation in 28a/28b. The combined old 24/25 snapshots are retired. Do not backport fixes into those retired copies; their replacements already retain the constructor, alias, native-exposure and import fixes. Native library construction and tuning material live in [appendices](appendices/README.md). Future incremental builds are specified in [incremental-builds.md](incremental-builds.md). ## Four README intentions to review Keep these four issues visible while reviewing the named chapters. Decisions may change the construction/escape boundary or later chapter splits. 1. **Construction (active):** final fields should be local SSA values during construction, including repeated assignments and loops, with field Stores at helper exits. Silent loss of writes is a bug; reject unsupported cases. Also decide whether to allow helpers after inlining and defer completion checks until SCCP. Those are separate from local field updates. The local-value implementation now supports final data fields in construction, escape, and modules, including constant defaults and loop Phis. Shared function declarations remain fixed. Validate this frontier before adjusting the broader constructor rules. 2. **Privacy:** underscore names select the public interface, but sibling access to private fields is not yet rejected. Confirm and enforce the intended source access rules. The proposed chapter boundary and library changes are recorded below; Cliff reviews that proposal before implementation. 3. **Class initialization:** review the corrected rule: A may start, initialize B, then resume. Passive references may cycle; active dependencies may not. Parents finish before children start. The README now matches this behavior; further semantic changes need an explicit decision. 4. **Escape summaries and ELF visibility:** analysis tracks unknown callers, while the current ELF writer exports retained named functions. Decide which symbols should be public and how that boundary relates to separate compilation. ### Privacy proposal for review Introduce enforced underscore privacy in **Modules and Lazy Class Initialization** (`chapter28a`). This is a visible language change: earlier snapshots allow underscore field access; from Modules onward, access must obey the declaring class's boundary. The teaching outline already places privacy here, alongside class names, ownership, and the public interface. The earlier escape snapshot does not filter fields by underscore spelling. Its private construction memory is a different concept. Review follow-up: preserve the distinction between export filtering and access checks. Before the 2026-10-24 cleanup, the first underscore helper in the numbered snapshots' tests was Chapter 19's `Chapter19Test.testString`, `_hashCodeString`. Renaming it to `hashCodeString` produces the identical LocalSched graph there: single-use inlining removes it regardless of spelling. In Chapter 25's copy of that test, the same rename retains an extra function Return. Underscore export filtering currently starts in Chapter 25 (and its Modules extraction), not Chapter 19. Old test class names inside newer snapshots do not identify when their current underscore behavior was introduced. Any access-check change must preserve the existing ability to hide helpers and classes from the public interface. Chapter 19's example now uses `hashCodeString` and field `hashCode`; all 42 Chapter19Test tests pass with the existing expected graph unchanged. Proposed rules: - A field or method beginning with `_` is accessible only from code in its declaring class, including its constructors and method bodies. Enclosing, nested, and sibling classes do not gain access to that field. A same-class method may access another instance's private fields; the receiver need not be exactly `self`. - A private class name is available in its declaring scope and within the class itself. For example, `App` may name its child `_Cache`, but that does not grant `App` access to `_Cache._data`. Code outside that declaring scope cannot bypass the restriction with a dotted path. Private ancestors also keep their descendants out of the public interface. Check both type names and class-value references, and distinguish naming a private class from using a public value returned by a factory. - Reads, writes, updates, and method references follow the same rule. Preserve the source owner and location when receiver types are unresolved; inlining must not change who has access. An unused result or a folded Load must not erase an illegal source access. - Native declarations obey the same source rules. A public wrapper or alias may deliberately expose a private native binding; no exception for `sys`. Source audit: - `sys/io.smp` calls `libc._exit` twice. Keep the native `_exit` declaration private in `sys/libc.smp`, add `val exit = { i32 status -> _exit(status); };`, and use `libc.exit` in IO. This preserves the native symbol and behavior. - Bitset's `_bits` and `_grow`, including `_grow(bit)._bits`, are used within the declaring struct and remain legal. Array helpers call their own `_grow`. These are the other underscore names in the bundled module library. - Several retained String spill fixtures use free functions outside `_String` to access `_hashCode`. They will need an explicit adaptation in this snapshot (for example, making that fixture field public), with any changed allocation expectations measured. Do not silently grant file-wide access to pass them. - The numbered Chapter 25 library has the same `_exit` accesses, and its `docs/examples/FileIO.smp` also calls `sys.libc._exit`. After approval, implement and test in Modules, update its English/Japanese READMEs with the explicit language boundary, and run the full module suite including bundled `sys` and native execution. Cover allowed same-class access, rejected cross-class access, private class lookup, and forward receiver types. Carry the rule and library adaptations into Chapter 28b, with import tests preserving the original source owner. Do not backport the new language restriction into Chapters 10-24 or the named pre-module snapshots. ## Investigate next Establish an earlier-chapter failure before changing compiler behavior. ### Prefix update of an enclosing class field The following returns 11 instead of 21 in numbered Chapter 25, Modules, and Separate Compilation: ```simple int calls=0; val next_noInline={ -> ++calls; }; return next_noInline()+10*next_noInline(); ``` The prefix path updates an enclosing parser slot instead of class memory. Postfix `calls++; return calls;` works and is used in the new chapter example. This is independent of importing IR. The stage audit also reproduced the instance-method form in Chapter 23, where methods first appear: ```simple struct C { int x=0; val inc={ -> ++x; }; }; var c=new C; return c.inc()+10*c.inc(); ``` It returns 11 instead of 21 in Chapters 23 and 26. Prefix lookup bypasses the ordinary field-access path. A fix should share name resolution with other reads/updates while preserving constructor locals, and propagate from 23 through 28b. No fix is included in the numbering change. ### Constructor loop with break/continue: worklist assertion This fails in construction and in the unchanged escape compiler before the final-field fix, even with a mutable field: ```simple struct C { int x=0; new C={int n -> for(int i=0;i