summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-25 11:06:34 -0700
committerCliff Click <cliffc@acm.org>2026-10-25 11:06:34 -0700
commitf258c28fb4fc98e472be2e57a2504dc1a955f2eb (patch)
tree68733de8c475792a7df4d86af6c28dfa3e255f1b /docs
parent69e4a21f71aca4954469063387063434af35e679 (diff)
downloadSimple-f258c28fb4fc98e472be2e57a2504dc1a955f2eb.tar.gz
Simple-f258c28fb4fc98e472be2e57a2504dc1a955f2eb.zip
Cleanup docs
Diffstat (limited to 'docs')
-rw-r--r--docs/appendices/README.md4
-rw-r--r--docs/appendices/current-spill-matrix.md14
-rw-r--r--docs/chapter-backports.md253
-rw-r--r--docs/chapter-split.md220
-rw-r--r--docs/incremental-builds.md63
-rw-r--r--docs/japanese-translation.md22
-rw-r--r--docs/regalloc-spills.md2
-rw-r--r--docs/roadmap.ja.md468
-rw-r--r--docs/roadmap.md750
-rw-r--r--docs/stage-audit.md113
10 files changed, 275 insertions, 1634 deletions
diff --git a/docs/appendices/README.md b/docs/appendices/README.md
index d7803c97..9e39770c 100644
--- a/docs/appendices/README.md
+++ b/docs/appendices/README.md
@@ -9,7 +9,3 @@ another compiler directory.
rematerialization, inlining, and historical measurements from the split's
original snapshots. [Measurement methods](../regalloc-spills.md) describe
what those numbers include.
-
-The [roadmap](../roadmap.md), [incremental build design](../incremental-builds.md),
-and [review queue](../chapter-backports.md) distinguish future work from current
-behavior. The [stage audit](../stage-audit.md) records known limits and cleanup.
diff --git a/docs/appendices/current-spill-matrix.md b/docs/appendices/current-spill-matrix.md
deleted file mode 100644
index df253a46..00000000
--- a/docs/appendices/current-spill-matrix.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# Current allocator comparison
-
-`make spill-stats` measures Chapters 20, 21, 22, 23, 24b, and 28b against the
-historical test cohorts. Cohort IDs and test names retain their old numbers;
-column headings identify the current compiler directories.
-
-These are separate from the dated [pre-split measurements](../regalloc-spills.md).
-After a successful run, `python build-support/spill-matrix.py --reuse --update-docs`
-updates only this table. Fresh logs use 24b/28b names so old 24/25 results cannot
-silently become measurements of new compiler snapshots.
-
-<!-- spill-matrix:start -->
-No post-split measurement has been published yet.
-<!-- spill-matrix:end -->
diff --git a/docs/chapter-backports.md b/docs/chapter-backports.md
deleted file mode 100644
index e7293d8c..00000000
--- a/docs/chapter-backports.md
+++ /dev/null
@@ -1,253 +0,0 @@
-# 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.
-
-### Narrow stores in the ideal evaluator
-
-The prefix-update regression exposed an independent evaluator bug. In Chapter
-23, this postfix-only example returns 25710 in Eval2 instead of 110:
-
-```simple
-struct C { u8 x=255; val next_noInline={ -> x++; return x; }; };
-var c=new C;
-val a=c.next_noInline();
-val b=c.next_noInline();
-return a+10*b+100*c.x;
-```
-
-`Eval2.store` copies the raw value into its Java object array. It does not
-truncate to the field width, even though Store optimization removes masks that
-machine stores perform implicitly. The native prefix-update regression checks
-that the stored byte wraps and the expression returns the converted value.
-Establish the first affected evaluator and check signed fields and floating
-rounding before propagating a fix. Do not change valid generated code to match
-an incorrect ideal evaluator.
-
-### SCCP function revival: Chapter 24
-
-`Opto.linkCG` uses `code.link(fidx)`, which clears a linker entry when its
-function is structurally dead. Chapter 25 uses the non-cleaning `_link(fidx)`
-while discovering calls, so temporarily disconnected functions can be revived.
-Chapter 24 already has `_link`; the question is whether its own unlinking and
-SCCP sequence can expose the same failure.
-
-Trace a function from removal of its unknown-caller edge through discovery of
-a real call. Preserve the distinction between unreachable control and a
-structurally deleted node. No earlier-chapter failure is established yet.
-Dependency propagation already exists in Chapter 24's SCCP; only port a
-specific missing dependency with a reproducer. Keep Chapter 25's escape and
-external-caller machinery out of this investigation.
-
-Investigation on 2026-10-19 found no cleanup loss. A shadow Opto checked the
-linker entry before and after every `linkCG` lookup while running all 513
-Chapter 24 tests: 787 SCCP runs, 297 lookups, 74 links to functions with only
-their null input remaining, and zero structurally dead targets or removed
-entries. All tests passed. The remaining null lookups are not evidence of a
-cleanup loss: their entries were already null before the lookup.
-
-The factorial trace shows the distinction: FunNode#1309 loses Start and has
-one input, four uses, and type TOP; it then reaches XCONTROL before a real
-call links it. `isDead()` stays false, since it requires no inputs, no uses,
-and a null type. Thus the observed temporary lack of callers does not trigger
-`link()` cleanup. Keep this candidate unconfirmed rather than backporting the
-Chapter 25 lookup change on textual differences alone.
-
-## Future compiler work
-
-### Deterministic inlining
-
-The parse-size cutoff can reject a function whose optimized body is small.
-After shrinking rewrites converge, choose one growing inline using current
-body sizes and a deterministic ranking. Cache sizes per convergence round;
-use stable call-site provenance to break ties, not worklist order or newly
-allocated node IDs. Avoid per-node dependencies and repeated whole-body scans
-while a large function gradually shrinks.
-
-The bounded boilerplate-inlining heuristic is already in Chapters 20-24.
-This item is the larger Chapter 25 redesign.
-
-### Conversion and BOTTOM-on-error contracts
-
-Coordinate these changes with the incomplete-type/conversion split:
-
-- Chapter 24 Loads supply a typed result even when they report an error.
- Changing that result to BOTTOM alone breaks incomplete loop typing and can
- obscure the intended diagnostic. Chapter 25's Convert nodes provide the
- surrounding typed result. Relevant existing cases include
- `testBrainFuck`, `testWhileWithNullInside`, `testNullGuardErrors`, and
- `testLinkedList0`.
-- Chapter 24 arithmetic also needs its typed fallback while forward references
- are unresolved. Returning BOTTOM confuses unresolved expressions with
- uninitialized fields (`testCoRecur`) and loses arithmetic diagnostics.
-
-Preserve the current contracts until the parser, conversions, loop bounds,
-and diagnostics can move together. Do not weaken narrowing assertions or
-expected errors to make an isolated backport pass.
-
-### Representation changes
-
-The approved split keeps incomplete types, numeric modes, conversions, guards,
-and symbolic fields together, then introduces private constructor memory in
-the construction chapter. They are not independent fixes to copy into earlier
-snapshots.
-
-Serialization, global identity remapping, and imported escape summaries belong
-with separate compilation. Escape analysis now has its own earlier snapshot after
-construction; keep its boundary open to review.
-
-### Selective loading of library IR
-
-Reliable incremental rebuilding is separate future work; see the
-[incremental build design](incremental-builds.md) for the stale-dependency
-example, required input tracking, rebuild propagation, and validation plan.
-
-The Separate Compilation README review found that importing only `sys.io.p`
-still loads all ten units in the bundled `sys.o`, including `aryu8`, `aryi64`,
-`scan`, and `adt.bitset`. All remain loaded through TypeCheck. Loading only
-needed library members is a desired improvement, not current behavior.
-
-Selection works between independent objects: a client of `Counters.o` leaves
-an unrelated `Unused.o` unloaded. Once selected, an object's entire saved IR
-is reconstructed, and `ParseAll.loadDeps` follows its recorded dependencies.
-Splitting the object alone is insufficient while the root's reexports and
-unused function bodies still pull in those dependencies. Design member-level
-IR loading and dependency discovery together; preserve type identity,
-initialization rules, and imported escape summaries. This is separate from
-whether imported code is initialized or emitted in the client's object.
-
-## Modules and separate compilation
-
-Class-cycle checking and CLInit runtime lowering belong in 28a/28b. The
-[module README](../chapter28a/README.md) explains their semantics; remaining
-argument, initialization and pointer plans live in the [roadmap](roadmap.md).
-Native code cannot receive classes; a native-startup/class-handoff policy is
-not planned. Current data pointers remain eight bytes.
-
-## Backport validation
-
-Introduce an independent fix in the earliest applicable chapter and propagate
-it through every affected snapshot. For correctness fixes, first reproduce the
-failure in the destination compiler. Preserve each chapter's representation
-and tutorial boundary.
-
-Run focused checks and the existing full Make suites for the affected compiler
-directories, for example:
-
-```sh
-make -k tests CHAPTERS="chapter20 chapter21"
-```
-
-Chapter 25's inherited tests do not validate earlier compiler implementations.
-Force rebuilds when older Makefiles miss dependencies, and rebuild serialized
-libraries when their compiler or object format changes. Keep execution and
-register-legality checks independent of spill expectations. Preserve unrelated
-edits, keep text LF-only, and run `git diff --check`.
diff --git a/docs/chapter-split.md b/docs/chapter-split.md
deleted file mode 100644
index 55551b27..00000000
--- a/docs/chapter-split.md
+++ /dev/null
@@ -1,220 +0,0 @@
-# Approved chapter split
-
-Cliff approved the seven-part split on 2026-10-19 and the final numbering on
-2026-10-24. The old combined Chapters 24 and 25 are retired; their history is
-available in Git. Every new directory is a complete compiler snapshot.
-
-| Previous directory | Final chapter |
-|---|---|
-| chapter-sccp | 24a: SCCP within a function |
-| chapter-interprocedural-sccp | 24b: SCCP across functions |
-| chapter-incomplete-types | 25: SSA before types are known |
-| chapter-construction | 26: Construction and private memory |
-| chapter-escape | 27: Escape analysis and unknown callers |
-| chapter-modules | 28a: Modules and lazy class initialization |
-| chapter-separate-compilation | 28b: Separate compilation |
-
-Keep 17a/17b. The other paired chapters extend one idea: 24a/24b goes from
-local to interprocedural SCCP; 28a/28b goes from compiling modules together to
-compiling them independently. Construction and escape remain separate topics;
-neither is presented as requiring the other.
-
-Inherited Java test names such as `Chapter24Test` and `Chapter25Test` retain
-their historical identities across snapshots. They are regression cohorts,
-not an index of the current teaching sequence. Historical allocator tables
-also retain their original labels and dates.
-
-Native library construction and optimizer tuning are now [appendices](appendices/README.md).
-The [roadmap](roadmap.md) and [backport queue](chapter-backports.md) own future work.
-
-The teaching pattern is to introduce a difficult idea, then show how to make
-it useful in a larger setting. Each chapter must remain a complete, runnable
-compiler snapshot that preserves the language supported by its predecessor.
-
-## Teaching sequence
-
-| Topic | Main idea | Endpoint |
-|---|---|---|
-| SCCP within a function | Optimistic types, reachable control, Phi inputs, worklists, fixed points, and loop widening. Keep calls conservative at their interfaces. | Fold loop-carried values and eliminate branches that pessimistic iteration cannot resolve. |
-| SCCP across functions | Discover call edges during analysis; merge arguments and returns; account for unknown callers and function pointers. | Specialize parameters, resolve call targets, handle recursion, and remove unreachable functions. |
-| SSA before types are known | Syntax and lexical binding choose graph shape. Keep scalar types, deferred numeric modes, conversions, guards, incomplete objects, symbolic fields, and removal of parser-supplied Load/Phi bounds together. | Compile forward definitions without provisional types determining graph topology; settle types and layouts afterward. |
-| Construction and private memory | Allocation helpers, hidden initializers, user constructors, private self-memory, field-completion checks, and explicit publication. | Preserve initialization and memory facts through constructor calls and publish a completed object. |
-| Escape analysis and unknown callers | Discover which aliases and functions can reach code outside the known graph. | Preserve exposed memory and callable functions while specializing private code. |
-| Modules and lazy class initialization | Multiple source files, namespaces, privacy, ownership, singleton storage, first-use initialization, parent order, cycle diagnostics, and lowering. | Compile sources together with defined class-initialization behavior. |
-| Separate compilation | Preserve types, ideal IR, and identities across independent compilations. | Build a library and client separately, optimize imported bodies, link remaining calls, and check initialization dependencies across imports. |
-
-The first incomplete-type chapter stays together. Its unresolved memory accesses
-must work before construction introduces private memory; defer the private
-construction protocol, not the machinery required to represent an unknown access.
-
-## SCCP boundary
-
-The first SCCP snapshot keeps unknown-caller Start inputs and disconnects call
-edges during the optimistic solve. Parameters retain their declared types;
-call results retain facts from the preceding pessimistic pass, which can be
-sharper than the written signature. Calls still have whole-memory effects.
-After SCCP, peepholes relink calls and FinalizeIR removes uncalled bodies while
-preserving named exports. This is an intermediate compiler design, not a
-textual division of Opto.java.
-
-Ordinary loop widening belongs in the first chapter. The second adds argument
-and result widening for recursion. Use `f(x-1)+1` to explain why these are
-separate data cycles: the recursive return value never crosses Parm(x).
-
-Chained comparisons do not need their own chapter. Their home is
-beside Chapter 23 short-circuit expressions: evaluate each operand
-once and evaluate later operands only when earlier comparisons succeed.
-The current Chapter 24 cold-loop-split allocator improvement belongs with the
-tuning appendix.
-
-## Construction and escape boundary to establish
-
-Separate an explicit memory-publication operation from the analysis that
-discovers exposure to unknown code.
-
-| Construction chapter | Escape-analysis chapter |
-|---|---|
-| Tracks private memory while an object is built. | Tracks aliases and functions exposed through memory, calls, and returns. |
-| Publishes initialized memory at an explicit boundary. | Propagates exposure through the reachable graph. |
-| Conservatively preserves unknown callers for surviving function addresses, following the current Chapter 24 policy. | Uses escape facts to determine which functions need unknown callers. |
-| Explains EscapeNode as a publication operation. | Explains the Start/Stop feedback cycle between known code and the external world. |
-
-Verify this split against constructor calls and memory summaries. The earlier
-snapshot can publish conservatively; the later one refines that behavior.
-The name EscapeNode does not require teaching the full escape analysis at
-the point where publication is introduced.
-
-`chapter26` now implements that explicit boundary. Hidden initializer
-and allocator functions carry whole private object memory; completion publishes
-fields into public aliases. The new constructor functions reject early passing
-or storing of `self`, including self-links, and access through a merged alias.
-These are deliberate limits for review with the next escape snapshot. Normal
-function addresses retain conservative unknown callers. Initializers capture
-enclosing values as hidden arguments; writing back to captures is rejected.
-Arrays follow the same construction/publication protocol. There are no modules
-or class singletons in this snapshot.
-
-Review on 2026-10-22 removed an unnecessary representation detour. Constructor
-fields now stay in local SSA values and ordinary Phis; helpers emit ordinary
-Stores at exit, with precise aliases gathered in MemMerge. Private memory is
-only the handoff between helpers and publication. No global escape discovery
-is needed to build that representation.
-
-Construction and escape discovery need not be taught in this order. Keep the
-current order provisionally, without inventing a constructor example to claim
-that dependency. The callback example now lives in the EA chapter.
-
-## Modules before separate compilation
-
-Teach module semantics with all source files compiled in one invocation.
-Include lazy initialization, parent requirements, and cycle checking there.
-Separate compilation then adds serialized ideal IR and types, GlobalBits
-identity remapping, imported type reconstruction and analysis, and Unlink
-before machine compilation. Extend initialization checks across imported
-bodies, preserving opaque CLInit nodes until lowering.
-
-Keep code ownership distinct from unknown-caller edges in both chapters.
-Keeping a function for emission must not imply arbitrary callers can reach it.
-
-## Appendices and future work
-
-- Native library construction: numeric C data symbols, address handling,
- modular sys, runtime and driver support, and larger examples. Preserve the
- native functionality already taught in earlier chapters.
-- Optimizer and backend tuning: existing cloning/inlining choices, spill
- ranking by live-range area and copy cost, rematerialization, and splitting
- policies. Compare equivalent programs when explaining costs.
-
-This split organizes implemented behavior. Deterministic inlining, argument
-arrays, static pre-initialization of classes, CFG frequency estimates, and
-constant instance-field storage remain future work. See the
-[backport queue](chapter-backports.md) and [roadmap](roadmap.md).
-
-## Renumbering and validation
-
-The first runnable extractions are
-[SCCP Within a Function](../chapter24a/README.md) and
-[SCCP Across Functions](../chapter24b/README.md), followed by
-[SSA Before Types Are Known](../chapter25/README.md),
-[Construction and Private Memory](../chapter26/README.md) and
-[Escape Analysis and Unknown Callers](../chapter27/README.md), and
-[Modules and Lazy Class Initialization](../chapter28a/README.md), and
-[Separate Compilation](../chapter28b/README.md).
-All seven main snapshots are extracted and numbered. Chained comparisons now
-start in Chapter 23 beside short-circuit expressions. The linear-history
-publisher follows the numbered directories, including lettered pairs.
-
-Validate each intermediate compiler with its own Make suite, including execution
-checks. Keep declarations, conversions, diagnostics, and type bounds consistent;
-do not weaken checks to make an intermediate snapshot pass. Rebuild serialized
-libraries when their compiler or object format changes.
-
-## Escape snapshot ready for boundary review
-
-`chapter27` adds function/alias exposure sets to TypeMem and closes the
-Start/Stop feedback cycle during SCCP. Known calls propagate memory summaries;
-exposed returns, fields, external arguments and native calls discover further
-addresses. Native calls contribute even on paths with no live Return. Function
-addresses kept entirely in known code no longer imply unknown callers.
-
-The [recursive callback example](../chapter27/README.md) now belongs in
-that chapter. Its base parameter becomes 2 while recursive calls remain.
-Returning the callback or a containing object, or handing it to native code,
-restores conservative arguments. FinalizeIR separates those analysis facts
-from the roots needed to emit code.
-
-Construction still keeps local field values and rejects early exposure of self.
-Both runnable snapshots are available for Cliff's promised review/play session.
-This extraction does not choose broader rules for partially initialized objects.
-No modules, class singletons, serialized IR or identity remapping are included.
-
-## Modules snapshot ready for review
-
-`chapter28a` compiles all discovered source files together. It adds class
-singletons, namespaces and export filtering, parent initialization, CLInit memory effects,
-cycle diagnostics, runtime lowering, and shared native class storage. Source
-discovery reads parents as well as referenced children. The bundled modular sys
-is supplied as source; building reusable libraries remains appendix material.
-
-There is no Serialize phase, object reader, GlobalBits remapping, or imported
-IR. LocalIds assigns dense IDs within the invocation. FinishCalls detaches
-analysis call edges after loop analysis, before scheduling or instruction
-selection. ELF emits all discovered live bodies in the selected entry object.
-
-The preceding construction representation remains: field values and loop Phis
-stay local, with Stores at helper exits. Constructor reads may see an unfinished
-object, but may never read an uninitialized field. The module snapshot checks
-this separately from completion and publication. Escape analysis still restores
-unknown callers when a private callback reaches native code, including on paths
-with no Return.
-
-The README's lazy lookup-table example is executable. Existing tests also cover
-source/type cycles, rejected initialization cycles, parent order, native cold/hot
-calls, shared storage, and ARM/RISC-V encoding. The construction/escape border
-remains open to Cliff's review; this extraction does not settle broader rules for
-publishing unfinished objects.
-
-## Separate compilation snapshot ready for review
-
-`chapter28b` adds saved types and ideal IR, `GlobalBits`
-identity remapping, object discovery, imported bodies, and `Unlink`. It carries
-Modules' deferred constructor parsing, local final-field values and loop Phis,
-converted private memory summaries, native callback exposure, and source-parent
-initialization order. Source privacy enforcement remains a separate review.
-
-The runnable example compiles a library and a client from separate source roots.
-The client allocates an imported struct whose constructor updates a final field
-in a loop, then calls a retained library function that updates shared state.
-The regression checks evaluation under three seeds and native cold/repeated
-calls. A second import test preserves unknown callers for a callback passed to
-native code. Existing import tests retain initialization-cycle diagnostics,
-shared class data, public type reconstruction, and native function thunks.
-
-Serialization now saves the class declarations of owned nested structs even
-when they are absent from the optimized graph's type closure. Otherwise a
-client can load the instance type but cannot find its allocation signature.
-An explicit source input is always recompiled; dependency objects may still
-be reused. The old incremental-rebuild experiment remains ignored.
-
-All seven main teaching boundaries now have numbered snapshots. Broader
-language choices and compiler improvements remain in the review queue.
diff --git a/docs/incremental-builds.md b/docs/incremental-builds.md
deleted file mode 100644
index 201922a0..00000000
--- a/docs/incremental-builds.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Incremental builds: future work
-
-Recorded after the Separate Compilation README review, 2026-10-24. This is a
-design outline, not a description of implemented incremental builds.
-
-## Current gap
-
-`CompUnit` decides whether to reuse an object when the unit is discovered. It
-checks its source timestamp and its dependencies' existing object timestamps.
-It does not settle the whole dependency graph before accepting saved IR.
-
-For example:
-
-1. A depends on B and has inlined some of B.
-2. B's source changes, leaving B's object unchanged.
-3. A client discovers A. A's check sees the old B object and accepts A's object.
-4. Later discovery notices that B needs rebuilding, without reconsidering A.
-
-The compiler can therefore reuse code based on stale bodies or constants.
-An unchanged public signature is insufficient: Simple imports implementation
-details for optimization as well as declarations for type checking.
-
-## Required pieces
-
-- Discover dependencies, mark changed units, and propagate that decision to
- dependents until it settles. Handle cycles as groups. Do this before loading
- IR that may be stale; newly discovered dependencies must also join the plan.
-- Record actual inputs. An object can own several source units, so track all
- of their sources and the objects resolved through library search paths.
- The current check assumes `buildDir/name.o`; a missing file has timestamp
- zero and does not trigger rebuilding. Missing inputs must invalidate or
- produce a useful error rather than silently accepting an old result.
-- Record compiler and serialization versions, target, ABI, and relevant
- options. Content hashes would also detect changes with preserved timestamps.
- Specify which changes require rebuilding source and which reject an
- incompatible source-free library.
-- Make build targets match output ownership. The old ignored `testModule0`
- expects separate A.o and A/B.o, while the current compiler can bundle several
- units into one object. The target must identify the complete set it owns.
-- Provide an "ensure current" build operation. Explicit source compilation
- currently always recompiles. An unchanged build should do no compilation or
- linking; a changed object or link input should trigger relinking.
-- Publish successful outputs without leaving a partial object accepted after
- failure, and keep the recorded inputs consistent with those outputs.
-
-Initially, rebuilding every dependent of a changed object is a reasonable
-conservative rule. Fine-grained interface/body fingerprints can come later.
-
-## Suggested first implementation
-
-Put a small build driver around the compiler with explicit object targets,
-recorded inputs, and dependency propagation. Keep individual compilation
-requests straightforward. A clean build and an incremental build must produce
-the same observable program behavior.
-
-Cover unchanged builds, direct and transitive source edits, inlined constants
-and bodies, cyclic dependencies, bundled sources, removed inputs, library-path
-changes, compiler/target changes, and failed builds. Use controlled timestamps
-or hashes instead of sleeps. Replace the ignored historical experiment with
-tests matching the chosen object ownership model.
-
-Selective library IR loading is separate future work. It can reduce compile
-cost, but is not required to make conservative incremental rebuilding correct.
diff --git a/docs/japanese-translation.md b/docs/japanese-translation.md
deleted file mode 100644
index 39383345..00000000
--- a/docs/japanese-translation.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Japanese translation / 翻訳の保守方針
-
-English is authoritative. The contributed Japanese translation is maintained on
-a best-effort basis; English edits and chapter reorganizations never wait for
-translation updates. Move Japanese files and update navigation when renumbering
-chapters; prose updates can follow separately. Contributions are welcome, without
-an ongoing maintenance obligation for the original translator.
-
-[英語版](../README.md)が正式な文書です。この日本語訳は寄贈されたもので、可能な範囲で保守されますが、
-英語版より更新が遅れることがあります。英語版の編集や章の再構成を、翻訳の更新待ちにすることはありません。
-章を移動・改番する際は、日本語ファイルも一緒に移動して章の見出しやリンクを更新し、本文の翻訳は後から更新できます。
-翻訳の改善は歓迎しますが、元の寄贈者に継続的な保守を義務付けるものではありません。
-
-初回の翻訳は英語版のコミット
-[`81b654d7`](https://github.com/SeaOfNodes/Simple/tree/81b654d76444d747fdf1d053760e507b50f26e18)
-を基にしています。2026年10月の目次・文法見出し・コード例・命令エンコーディング・
-`C0DE` ヘッダに関する文書修正も反映しています。
-各文書の English リンクは現在の英語版を指します。更新されていない箇所の原文を確認するには、
-上記コミットの対応するファイルを参照してください。新しい章が未翻訳の場合は、その旨を示して英語版にリンクできます。
-
-
-[日本語の紹介に戻る](../README.ja.md)
diff --git a/docs/regalloc-spills.md b/docs/regalloc-spills.md
index 71bab467..a4ca818f 100644
--- a/docs/regalloc-spills.md
+++ b/docs/regalloc-spills.md
@@ -3,7 +3,7 @@
This is the dated **pre-split** comparison. Its Ch 24/25 columns describe the
retired combined snapshots, not today's Chapter 25 (incomplete types). Current
measurement tools target 24b/28b and publish a
-[separate table](appendices/current-spill-matrix.md). The historical numbers
+[separate table](../skills/current-spill-matrix.md). The historical numbers
below remain unchanged.
Read a row left to right to follow a fixed cohort through successive compilers.
diff --git a/docs/roadmap.ja.md b/docs/roadmap.ja.md
index 0af228a5..a44afab5 100644
--- a/docs/roadmap.ja.md
+++ b/docs/roadmap.ja.md
@@ -1,455 +1,33 @@
-# ロードマップ
-
-この設計ノートは旧第25章から移したものです。初期の節には、現在の第25〜28b章で
-実装済みの機能について検討した案も含みます。すべてが未実装という意味ではありません。
-現状と残る課題は[監査記録](stage-audit.md)、増分ビルドは[設計メモ](incremental-builds.md)を参照してください。
+# コンパイラのロードマップ
[English](roadmap.md) | 日本語
-この文書は [ROADMAP.md](roadmap.md) の日本語訳です。原文の設計案と未解決の問いを、そのまま設計案として記しています。
-
-## 分割コンパイル
-
-未知の前方参照をどう扱うか? H-M は使わないので、単一化も行わない。
-関数以外の前方参照を認めないことにする……関数なら、定義した時点ですぐにシグネチャを提供できる。
-
-案 A:FRefNode を削除し、すべてのバグを直す。
-案 A の問題:相互再帰を使えるようにしたい。
-例:`val even = { int x -> x ? odd(x-1) : true; }; val odd = { int x -> x ? even(x-1) : false; };`
-
-案 B:型は順序どおりに定義する必要があるが、それ以外の関数には順序を要求しない。
-`new T` ならエラーにできるが、`fref.field`、`fref()`、`fref op fref`、`fref[]` ではできない。
-
-あらゆる場所で Type.BOTTOM をパーサーの要件に合わせて「引き上げる」必要がある。
-FRef からフィールドをロードするには、FREF を FIELD のある TSTRUCT への TMP に引き上げる必要がある……。
-実際には、FREF が正しくなると局所的に仮定するだけだ。型は任意のコードから来るので、
-アクセスできず、引き上げられない。TMP は nullable かもしれない(後でエラーにすべき)。
-TSTRUCT は無名にでき、無名になるだろう。これは、すべての TSTRUCT を無名にすることを意味する。
-
-問題は、未知・遠隔・外部・前方の参照にある。
-
-FRef を*少しでも*認めると、すべての処理が FRef 型に遭遇することを考慮しなければならない。
-同じスコープの関数で認めると、上の odd/even の例が使える。
-同じスコープの構造体で認めると、相互再帰的な構造体が使える。
-スコープの外へ昇格させる際には外部の検索を試み、見つからなければ失敗する。
-
-任意の使い方の例:`sys.fld`。`sys` の検索に失敗したら、次のどちらかを推測しなければならない。
-前方参照で問題なく、間もなく定義されるのか……それとも今すぐ外部を検索するのか。
-さらに、使い方によっては問題の発覚が遅れる。
-```java
-// Extern or Future `sys` being returned.
-val foo { -> return sys; }
-
-// foo() returns FRef, so Bottom, so the `.bar` has no type
-// to do field lookups
-val main { arg -> foo().bar }
-
-// HERE: Parser finds `sys` OR NOT?!?!?!
-val sys??? = user_stuff....;
-
-```
-
-行き着く先は、パーサーが一切エラーを出さず、盲目的な AST のように SSA を構築し、
-不適切な型だらけのグラフを結線するだけになることだ。
-必要なこと:パーサーを導く型をなくす! 構文だけを使う!
-
-(明らかな小さな問題:浮動小数点数へ拡張するかどうか。)
-修正:たとえば整数演算を挿入する。両方の入力が isa-Int であり、isa-Float に引き上げられなくなるまでは、
-戻り値の型を Int と Float の MEET とする。
-
-メソッド呼び出しで起こり得る問題:
-`UNKNOWN_STRUCT_BOT.UNKNOWN_FIELD ( ARGS ); // Insert SELF OR NOT?`
-— SELF を挿入するか?
-修正案:常に SELF 引数があると仮定し、静的と証明できる場合は null にする。
-最適化:定数パラメータをシグネチャから削除するか? *定数*パラメータは、
-*パーサー*の時点で定数でなければならない。そうでなければ未知の呼び出し元がないことが必要になる
-(したがって局所的な最適化になる)。
-修正案:SELF 引数を*最初*ではなく*最後*に置くと、不要になった場合に削除しやすいか?
-
-Load は ConFldOff を捨て、名前を保持する。
-Load はスケーリング前の添字を保持し、添字入力を持つ。構造体ではこの入力は null。
-Ptr Base が*確定*した後で基底の配置を行い、添字の計算を畳み込める。
-
-- `Load(ctrl, base, null );` — フィールド名は内部に持つ。
-- `Load(ctrl, base, index_math );` — フィールド名は `[]`。
-- `Store(ctrl, base, null , val);`
-
-問題:エイリアス情報がない!
-
-案 C:直接呼び出し `odd()` と型では FRef を認める。それ以外はすべて*引き上げ*が必要。
-
-## 構造体と配列の統合
-
-構造体のフィールドは名前で索引付けされ、配列の要素は数値で索引付けされる。
-この2つの考え方は両立する、という発想です。
-C 言語では古くからこの考え方を使っています。通常の C の構造体の後に配列を続け、
-通常の配列構文で索引アクセスできます。
-
-別の方法として、配列へのポインタをフィールドに保持すると、間接参照が1つ増える代わりに柔軟性が得られます。
-特に、配列を(通常はより大きな配列に)交換できます。
-これは、広く使われる汎用コンテナ `Vector` や `ArrayList` の基礎です。
-
-```java
-struct str {
- int hash; // A cache of the strings hash code
- u32 #; // The array length
- u8 []; // Array of bytes
-};
-
-str X = "abc";
-print(X.hash); // Read the hash field
-X[0]=='a'; // Read array element 0
-X#; // Length of the array
-
-```
-
-ここでは、`#` というフィールドが配列の長さを保持し、`[]` というフィールドが実際の配列です。
-メモリ内では、この配列がほかのフィールドの直後に続きます。
-可変長配列の別の例を示します。
-
-```java
-struct vecInt {
- u32 size; // Actual number of elements
- u32 #; // The array length or capacity
- int []; // Array of integers.
-};
-```
-
-明らかな制約として、配列のサイズを直接変更することはできません。
-先頭のフィールドと同じメモリブロックに実際に配置されているからです。
-このような `vecInt` を、より大きい新しい `vecInt` に*再割り当て*することはできますが、
-元の `vecInt` は解放されます。同じ `vecInt` の参照を永遠に使い続けることはできません。
-
-名前付きフィールドはいくつあってもかまいません。
-
-```java
-struct Class {
- !str !className;
- !str !professor;
- int time;
- int credits;
- !Class !prerequisite;
- u16 #; // Limit of 65535 students per class
- Student [];
-};
-```
-
-自己参照も使えます。
-
-```java
-struct NTree {
- Some val;
- u8 #; // Length is 0-255
- NTree []; // More NTrees
-};
-```
-
-構文規則は次のとおりです。
-
-- 最後のフィールドの名前は `[]` で、どの型でもよい。
-- 最後から2番目のフィールドの名前は `#` で、配列の最大長を表す符号なし整数型でなければならない。
-- ` []` の前に空白が必要になるかもしれない。
-
-### コンストラクタと配列
-
-割り当てには配列の長さを含め、コンストラクタも含められます。
-`new NTree{val=17;}[2];`
-
-コンストラクタは省略できますが、配列の長さは省略できません。
-
-配列を初期化するための任意の関数を使うと、一度だけ書き込む final 配列を作れます。
-`new u8[buffer#,{ u32 idx -> buffer[idx].toUpperCase() }]`
-
-### 配列の最大長の変更
-
-範囲チェックのある小さな配列を大量に使う場合、配列の長さのために丸々4バイトを確保すると、
-配列のオーバーヘッドが大きく増えることが問題になります。
-Simple では最大長を小さくできます。ただし、最大長が異なる配列は別の型として扱います。
-
-```java
-struct x0 { u8 #; u8[]; }; // Array limited to 0-255 length
-struct x1 { u16 #; u8[]; }; // Array limited to 0-65535 length
-struct x2 { u32 #; u8[]; }; //
-struct x3 { u64 #; u8[]; }; //
-
-x0 x = "abc"; // 4 bytes total: [3, 'a', 'b', 'c']
-x1 y = "def"; // 6 bytes total: [3, 0 , 'd', 'e', 'f', 0,]; 1 pad byte to acheieve 2-byte alignment
-x = y; // ERROR, "x1 is not x0", no auto-widening
-x += y; // OK, 7 bytes total: [6, 'a', 'b', 'c', 'd', 'e', 'f']
-y += x; // OK, 8 bytes total: [6, 0 , 'd', 'e', 'f', 'a', 'b', 'c']
-
-x += "VeryLongString.... ....255_chars"; // Runtime RangeCheck
-
-// Explicit conversion to widen string
-y = "" + x;
-```
-
-### 拡張可能な配列・文字列の2つの形:間接参照を増やすかどうか
-
-間接参照を1つ増やすと、Java の `ArrayList` や C++ の `Vector` のようになります。
-
-増やさない場合、拡張可能な配列を伸ばす呼び出しは、新しいオブジェクトを返す可能性があります。
-拡張は必要な場合だけ行います。
-
-```java
-val vec1 = new vecInt[0].add(2); // len=1, capacity=1
-val vec2 = vec1.add(3); // NEW !vecInt !returned, only is deleted; len=2; capacity=2;
-vec1[0]; // ERROR, vec1 has been freed by call to `vec1.add(3)`
-vec2[0]; // OK
-vec2[1]; // OK
-vec2[2]; // Runtime error, AIOOBE
-```
-
-## 文字列の実装
-
-既定の文字列は「str」「cstr」「ustr」などの名前を持ちます。
-
-常に unicode8 を使い、u8 を明示的に操作します。
-Unicode の「文字」は、基礎となる実装の上に関数呼び出しとして提供します。
-おそらく別の文字列クラスで実装することになります。
-
-## 既定の文字列
-
-連結によって効率的に拡張でき、さまざまな IO/printf 関数をサポートします。
-明示的に要求すれば、基礎となる配列を可変な状態で共有できます。
-既定では常に、非共有時は可変、共有時は読み取り専用です。
-
-```java
-struct str {
-
- // Add a string to the string, possibly growing
- val add = { str str ->
- val self = this;
- for( int i=0; i<str#; i++ )
- self = self.add(str[i]);
- return self;
- };
-
- // Add an char to the string, possibly growing
- val add = { u8 e ->
- if( len >= # ) return copy(# ? #*2 : 1).add(e);
- [size++] = e;
- return this;
- };
-
- // Copy 'this' to a new larger size
- val copy = { int sz2 ->
- val v2 = new str[sz2];
- for( int i=0; i<len; i++ )
- v2[i] = [i];
- v2.len = len;
- sys.libc.free(this); // Needs a better Mem Management solution
- return v2;
- };
-
- val print { -> sys.libc.write(1/*stdout*/,[]/*array base as argument to C*/,len); return this; }
-
- u32 len; // In-use size
- u32 #; // Max length is 4Gig, although variants can request smaller lengths
- u8 []; // Character data
-};
-```
-
-### Final な文字列
-
-**不変**な文字列を意図しており、**安全な**文字列の基礎にも使えるかもしれません。
-一度に全体を作成する必要があり、おそらく防御的コピーも必要になります。
-
-```java
-struct sstr {
- // Possible static call syntax; no references to "this"
- val make { str str -> new sstr[str#,str.at] };
-
- // Array contents are immutable.
- // Still figuring out good syntax for this.
- u8 #;
- u8 [~]; // Middlin '~'? Makes primitive array contents *immutable* and requires constructor syntax
-};
-
-// Construction requires a function that produces the array contents.
-// Here we are defining a defensive copy over `buf`.
-sstr safe = new sstr[buf.len,{ int idx -> buf[idx]; }];
-sstr safe = sstr.make("abc"); // Defensive copy is made
-```
-
-### 拡張可能な文字列(StringBuilder または StringBuffer)
-
-この API は `StringBuilder` スタイルの代替としてそのまま使えることを意図しており、
-使うたびに間接参照が1つ増えます。
-
-```java
-struct xstr {
- !str !_str; // The extra indirection is here
- val add = { str str -> _str = str.add2(str); };
- val write = { int fd -> _str.write(fd); };
-};
-```
-
-### Unicode 文字列
-
-この API は、通常の `str` の上で Unicode の文字を操作できるようにすることを意図しています。
-
-```java
-struct ustr {
- // Assuming idx is at the start of a character, return the character
- // as a 32b integer. Returns junk integer if not at a character start.
- // For all ASCII strings this will amount to a simple byte load.
- // For bytes with high order bits set, this may read 1-4 characters.
- val at = { int idx -> ... };
-};
-// Unicode character iterator
-struct ucharator {
-// Return successive unicode character codes
-};
-```
-
-### 「C」文字列
-
-ゼロ終端の文字列ですが、長さを直接取得できる必要があります。
-
-```java
-struct cstr {
- u8 #; // length including the trailing zero
- u8[]; // always ends in a zero byte; suitable for direct passing to C string functions
-};
-```
-
-### 「german string」:レジスタに格納できる非常に短い文字列
-
-メモリ内では、長さを表す1バイト(3ビット?)に続いて0〜7文字を格納し、最大8文字です。
-64ビットのレジスタに収まります。
-
-```java
-struct gstr { // aka germanString, or blend string and register "streg"
- u3 #; // Size is 0-7 bytes???
- u8 []; // Up to 7 bytes
-}
-// Using inlined object (see below). All these strings are short and are
-// represented as packed integers in a 64b register.
-*gstr prize1 = "gold";
-*gstr prize2 = "silver";
-*gstr prize3 = "bronze";
-
-```
-
-### Main は `val main = { str[] args -> ...}` になる
-
-## 構造体のインライン化
-
-構造体は通常、参照として扱いますが、「内容(contents of)」と読む `*` 演算子を使って
-値として扱う形へ変換できます(この名前は、たとえば `inline` に変えるかもしれません)。
-
-これは名前空間の変更だけです。内部の構造体の寿命を完全に消費しない限り、そのアドレスは取得できません。
-「外部への流出」は認めません。
-
-```java
-// 2 64-bit words, no other overheads
-struct Complex { f64 x,y; val len = { ->Math.sqrt(x*x+y*y); }; };
-
-// Current Simple rules: always by-reference
-struct ByRef {
- !Complex !c; // 4-byte pointer to a Complex
-};
-print(new ByRef.c.y); // Lookup requires 1 extra memory load from ref to c
-
-// New behavior: by value (inlining a struct)
-// The '*' syntax indicator can be something else, e.g. a keyword "inline"
-// I am pronouncing '*' as "contents of"
-struct ByValue {
- *!Complex !c; // c is inlined, full 16 bytes into ByValue
-};
-print(new ByValue.c.y); // x,y inlined into ByValue, no extra memory load
-
-// Mixing Refs and Struct Values. Basically, a ref can be converted
-// to a value by taking the "contents of" the ref, and values cannot
-// be *converted* to a ref, although they can be copied over a ref.
-ref. c = val.c; // Error, mixing refs and values
-ref.*c = val.c; // Allowed, whole structure copy. Does not allocate, requires ref.c not-null
-val. c = ref.c; // Error, mixing refs and values
-val. c = *ref.c; // Allowed, whole structure copy
-ref. c = ref.c; // Allowed, pointer copy
-val. c = val.c; // Allowed, whole structure copy.
-val *c = val.c; // Error, cannot take "contents of" a value
-
-// Alternative syntax, to avoid the "contents of" being on LHS and field applying to being on RHS:
-ref.c = val.*c; // Assign into ref.c the "contents of" val.c
-
-// Arrays of inlined structures
-var ary = new *Complex[99]; // Array of 99 !Complex !objects, inlined
-
-// Calling methods has the same syntax
-ref.c.len();
-val.c.len();
-
-// Function arguments use the same typing, so can pass-by-value
-val math.sin = { *Complex c -> ... }; // Passes a complex by value
-math.sin(ref.*c); // Requires de-reference to pass by value
-math.sin(val. c); // Pass by value
-
-```
-
-## ほかの章のロードマップ
-
-`&&` と `||`。
-`int` を `i32` に縮小する。
-`TypeMemPtr` を4バイトに縮小する。`mmap` を使い、ヒープを下位4Gの領域に置く。
-パーサーの既定の for ループ構築、または部分的なループ剥離。
-`for( init; test; next ) body` は、次のようになる。
-```java
-{ init; // Normal scope entry to bound lifetime of index variable
-if( !test ) { // Zero-trip count test
- do {
- body;
- next;
- } while( test ); // Exit test at loop bottom by default
-} };
-```
-
-## `&&` と `||`
-
-論理演算子 &&(AND)と ||(OR)は短絡評価を行います。
-最初の条件だけで結果が決まるときは、第2の条件の評価を省略できます。
-
-- `&&` は最初のオペランドが偽なら評価を止めます。
-- `||` は最初のオペランドが真なら評価を止めます。
-
-これらは制御フローを読みやすくする糖衣構文であり、実行モデルに新しいノードを作りません。
-
-`&&` と `||` の構文は、制御フローだけを変える単純な糖衣構文であり、新しいノードを導入しません。
-
-次の例を考えます。
-```java
-int a = 1;
-int b = 0;
+未完了の作業と将来の言語設計案の要約です。現在の言語仕様や実装済みの機能を
+示すものではありません。詳細と最新の判断は[英語版](roadmap.md)を参照してください。
-if(a++ || b++ ) {
- if(b == 0 && a == 2) {
- sys.io.p("Or");
- }
-} else{
- sys.io.p("And");
-}
-return 0;
-```
+## 正確性とコンパイル
-- `a++` は1(真)と評価されるので、`b++` は評価されません。
-- その結果、`b` は0のままで、`a` は2になり、「Or」が表示されます。
+- 理想 IR の評価器で、狭いフィールドへの Store に必要な切り詰めと丸めを行う。
+- 依存関係全体を調べ、変更を伝播してから保存 IR を再利用する、正しい増分ビルドを実装する。
+- ライブラリオブジェクト全体ではなく、必要なメンバーの IR を選択してロードする。
+- 最適化後の関数サイズと安定した順位を使い、インライン化の選択を決定的にする。
+- CFG の実行頻度推定、ループの回転、定数インスタンスフィールドの格納省略を検討する。
-```java
-int a = 1;
-int b = 1;
+## 言語とランタイム
-int x=1;
-int y=1;
-int z=0;
+- アンダースコアによる公開インターフェースの選別に加え、ソースの private アクセス規則を決めて強制する。
+- 未完成の self をヘルパーへ渡せる条件と、コンストラクタの完了検査を行う時点を検討する。
+- ELF シンボルの可視性と、未知の呼び出し元・コード出力の所有権を区別する。
+- クラス初期化子の整数引数を引数配列に置き換える。
+- 初期化全体を静的データで表せるクラスについて、実行時の初期化呼び出しと状態を省略する。
+- コンパクトなコード/データ領域、ネイティブポインタ型、GC に依存しない寿命管理を設計する。
-int g = x++ && y++ && z++;
-...
-```
+## データとライブラリの設計案
-この例では、次のようになります。
+- 名前付きフィールドの末尾に配列を配置する構造体と、異なる幅の長さフィールド。
+- 要素を生成する関数を使う配列初期化。
+- 可変・不変・C 互換・Unicode・短い値文字列の各用途に応じた文字列ライブラリ。
+- 構造体のインライン格納と値渡し。
+- `int` の既定幅を現在の `i64` から `i32` に変えるかどうか。
-- `x++` は真(1)なので、`y++` を評価します。それも真です。
-- 続いて `z++` を評価します。これは偽(0)です。
-- `&&` はすべての条件が真であることを要求するため、最終結果 `g` は0になります。
-- 偽になるオペランドまでのすべてのオペランドを評価するため、`x`、`y`、`z` はすべてインクリメントされます。
+これらの言語変更には、それぞれ設計判断と導入する章の境界が必要です。
diff --git a/docs/roadmap.md b/docs/roadmap.md
index aad2d9ca..d441abb9 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -1,533 +1,285 @@
-# Compiler roadmap and design notebook
-
-This notebook preserves the design discussion from the former combined Chapter
-25. Early sections include alternatives considered while implementing features
-now taught in Chapters 25–28b; they are not all pending tasks. The
-[stage audit](stage-audit.md) distinguishes current behavior from remaining gaps.
-The [incremental-build design](incremental-builds.md) is a separate future item.
-The final section records the outstanding class-initialization and compiler
-follow-ups. Keep speculative language/library designs as proposals.
-
-## Separate Compilation
+# Compiler roadmap
English | [日本語](roadmap.ja.md)
+Open compiler work and language proposals, reviewed against the current
+snapshots on 2026-10-25. These are future changes, not promises about the
+language implemented by the tutorial. Language changes still need their own
+design decisions and chapter boundaries.
-How to handle unknown forward ref?
-No H-M, so no unification.
-Demand no forward refs beyond functions... which will provide immediate signatures when def'd.
-
-Plan A: Remove FRefNode; fix all my bugs.
-Fail A: I want mutual co-recurusion to work
-Example: `val even = { int x -> x ? odd(x-1) : true; }; val odd = { int x -> x ? even(x-1) : false; };`
-
-Plan B: Require types ordered, but not any other fcn. `new T` can complain,
-but not `fref.field` or `fref()` or `fref op fref` or `fref[]`
-
-Requires "lifting" Type.BOTTOM to the parser requirements everywhere.
-So loading a field from an FRef requires: lift the FREF to a
-TMP-to-TSTRUCT-with-FIELD... actually, just locally assume FREF will become
-correct. Can't Lift it, no access, since type comes from random code.
-TMP might be nullable (should error later).
-TSTRUCT can/will be unnamed. Implies ALL TSTRUCT is unnamed.
-
-Issue is some unknown/remote/external/forward-ref.
-
-Allowing an FRef *at all* means everybody has to deal with seeing an FRef Type.
-Allowing it for functions in same scope allow the above odd/even case .
-Allowing it for structs in the same scope allows for co-recursive structs.
-Promoting out-of-scope attempts the external lookup, then fails.
-
-Random junk usage: `sys.fld`. Looking up `sys` fails, now has to
-guess: fref is ok, will be defined shortly... OR extern lookup now.
-Then some usage delays trouble:
-```java
-// Extern or Future `sys` being returned.
-val foo { -> return sys; }
-
-// foo() returns FRef, so Bottom, so the `.bar` has no type
-// to do field lookups
-val main { arg -> foo().bar }
-
-// HERE: Parser finds `sys` OR NOT?!?!?!
-val sys??? = user_stuff....;
-
-```
-
-Which gets to: parser never complains, builds SSA like a blind AST,
-just wires up a graph with bad types all around. Requires: No Types
-to guide parser! Just Syntax!
-
- (Obvious minor fail: widen floats- or-not) Fix: insert e.g. int-oper, return
- type is MEET of Int,Float until both inputs are isa-Int and cannot lift to be
- isa-Float
-
- Possible method call fail:
- UNKNOWN_STRUCT_BOT.UNKNOWN_FIELD ( ARGS ); // Insert SELF OR NOT?
- Possible fix: always assume a SELF arg, which is null for provable statics.
- Optimization: constant parms get dropped from sig? *Constant* parms
- must be constant from *Parser*, or else no unknown callers (so local opts).
- Possible fix: SELF arg is *last* not *first*, easier to drop if dead?
-
- Load drops ConFldOff, keeps name.
- Load keeps index unscaled, has index input, which is null for structs.
- After Ptr Base is *closed*, base layout can happen, can fold index math.
- - Load(ctrl, base, null ); // field name internal
- - Load(ctrl, base, index_math ); // field name=='[]'
- - Store(ctrl, base, null , val);
-
- FAIL: No Alias Info!
-
-
-Plan C:
- FRefs allowed for direct calls `odd()`, and for Types.
- All other cases must *lift*.
-
-
-## Unifying Structs and Arrays
-
-The idea is that structs have fields indexed by names, and arrays have fields
-indexed by numbers, and these ideas are compatible with each other. This idea
-has been used by the C language for a long time - an array can follow a normal
-struct C and can index it with the usual array syntax.
-
-The alternative, using a field to hold a pointer to an array, exchanges some
-flexibility for an extra indirection. The obvious flexibility allows swapping
-the array out (generally for a larger one) and this is the basis of very common
-`Vector` or `ArrayList` generic containers.
-
-
-```java
-struct str {
- int hash; // A cache of the strings hash code
- u32 #; // The array length
- u8 []; // Array of bytes
-};
-
-str X = "abc";
-print(X.hash); // Read the hash field
-X[0]=='a'; // Read array element 0
-X#; // Length of the array
-
-```
-
-Here, the field named `#` holds the array length and the field named `[]` is
-the actual array, which follows the other fields directly in memory.
-Here is another example for variable length array:
-
-```java
-struct vecInt {
- u32 size; // Actual number of elements
- u32 #; // The array length or capacity
- int []; // Array of integers.
-};
-```
-
-The obvious limit here is that the array cannot be directly resized; it is
-literally in the same memory block as the leading fields. Such a `vecInt` can
-be *re-allocated* to a new larger `vecInt`, but the original `vecInt` will be
-reclaimed - you cannot use the same `vecInt` reference forever.
-
-Any number of named fields are allowed:
-
-```java
-struct Class {
- !str !className;
- !str !professor;
- int time;
- int credits;
- !Class !prerequisite;
- u16 #; // Limit of 65535 students per class
- Student [];
-};
-```
-
-Or self-reference:
-
-```java
-struct NTree {
- Some val;
- u8 #; // Length is 0-255
- NTree []; // More NTrees
-};
-```
-
-The syntax rules are:
-- the last field is named `[]` and can be of any type.
-- the second-to-last field is named `#` and must be some unsigned integer type
- representing the maximum array length.
-- may require a leading space in front of ` []`
-
-
-
-### Constructors and Arrays
-
-The allocation includes the array length, and can include a constructor:
-`new NTree{val=17;}[2];`
-
-The constructor is optional, the array length is not.
-
-Optional function for initializing arrays, allows for write-once final arrays:
-`new u8[buffer#,{ u32 idx -> buffer[idx].toUpperCase() }]`
-
-
-
-### Changing array max length
-
-An issue for large numbers of range-checked small arrays is that reserving a
-full 4 bytes for array length can substantially increase the array overhead.
-Simple allows for arrays to have smaller max lengths, although these are
-treated as a different type than arrays with different max lengths.
-
-```java
-struct x0 { u8 #; u8[]; }; // Array limited to 0-255 length
-struct x1 { u16 #; u8[]; }; // Array limited to 0-65535 length
-struct x2 { u32 #; u8[]; }; //
-struct x3 { u64 #; u8[]; }; //
-
-x0 x = "abc"; // 4 bytes total: [3, 'a', 'b', 'c']
-x1 y = "def"; // 6 bytes total: [3, 0 , 'd', 'e', 'f', 0,]; 1 pad byte to acheieve 2-byte alignment
-x = y; // ERROR, "x1 is not x0", no auto-widening
-x += y; // OK, 7 bytes total: [6, 'a', 'b', 'c', 'd', 'e', 'f']
-y += x; // OK, 8 bytes total: [6, 0 , 'd', 'e', 'f', 'a', 'b', 'c']
-
-x += "VeryLongString.... ....255_chars"; // Runtime RangeCheck
-
-// Explicit conversion to widen string
-y = "" + x;
-```
-
-
-### Two flavors of extendable arrays/strings: an extra indirection or not
-
-With an extra indirection you get e.g. Java `ArrayList` or C++ `Vector`.
-
-Without, then any call which extends the extendable array return a potentially
-new object, only growing as needed.
-
-```java
-val vec1 = new vecInt[0].add(2); // len=1, capacity=1
-val vec2 = vec1.add(3); // NEW !vecInt !returned, only is deleted; len=2; capacity=2;
-vec1[0]; // ERROR, vec1 has been freed by call to `vec1.add(3)`
-vec2[0]; // OK
-vec2[1]; // OK
-vec2[2]; // Runtime error, AIOOBE
-```
-
-
-## A String Implementation
-
-Default strings have names like "str", "cstr", "ustr" or such.
-
-Always unicode8 with explicit u8 manipulations. Unicode "characters" will come
-as function calls over the base implementation, probably in another string class.
-
-## Default string
-
-Efficiently growable via concantenation. Supports a variety of IO/printf functions.
-The underlying array can be shared mutable if you ask for this.
-The defaults will always be private mutable and read-only shared.
-
-```java
-struct str {
-
- // Add a string to the string, possibly growing
- val add = { str str ->
- val self = this;
- for( int i=0; i<str#; i++ )
- self = self.add(str[i]);
- return self;
- };
-
- // Add an char to the string, possibly growing
- val add = { u8 e ->
- if( len >= # ) return copy(# ? #*2 : 1).add(e);
- [size++] = e;
- return this;
- };
-
- // Copy 'this' to a new larger size
- val copy = { int sz2 ->
- val v2 = new str[sz2];
- for( int i=0; i<len; i++ )
- v2[i] = [i];
- v2.len = len;
- sys.libc.free(this); // Needs a better Mem Management solution
- return v2;
- };
-
- val print { -> sys.libc.write(1/*stdout*/,[]/*array base as argument to C*/,len); return this; }
-
- u32 len; // In-use size
- u32 #; // Max length is 4Gig, although variants can request smaller lengths
- u8 []; // Character data
-};
-```
-
-
-### A Final String
-
-Intended to be a **immutable** string, possibly used as a base for a **secure**
-string. This needs to be created all at once, and probably requires a
-defensive copy.
-
-```java
-struct sstr {
- // Possible static call syntax; no references to "this"
- val make { str str -> new sstr[str#,str.at] };
-
- // Array contents are immutable.
- // Still figuring out good syntax for this.
- u8 #;
- u8 [~]; // Middlin '~'? Makes primitive array contents *immutable* and requires constructor syntax
-};
-
-// Construction requires a function that produces the array contents.
-// Here we are defining a defensive copy over `buf`.
-sstr safe = new sstr[buf.len,{ int idx -> buf[idx]; }];
-sstr safe = sstr.make("abc"); // Defensive copy is made
-```
-
-
-### A Extendable String (aka StringBuilder or StringBuffer)
-
-This API is intended to be a drop-in for a `StringBuilder` style, and takes an
-extra indirection with each usage.
-
-```java
-struct xstr {
- !str !_str; // The extra indirection is here
- val add = { str str -> _str = str.add2(str); };
- val write = { int fd -> _str.write(fd); };
-};
-```
-
-### A Unicode String
-
-This API is intended to support unicode character manipulation over a plain `str`
-
-```java
-struct ustr {
- // Assuming idx is at the start of a character, return the character
- // as a 32b integer. Returns junk integer if not at a character start.
- // For all ASCII strings this will amount to a simple byte load.
- // For bytes with high order bits set, this may read 1-4 characters.
- val at = { int idx -> ... };
-};
-// Unicode character iterator
-struct ucharator {
-// Return successive unicode character codes
-};
-```
-
-### A "C" string
-
-A zero-terminated string, but the length has to be available directly
-
-```java
-struct cstr {
- u8 #; // length including the trailing zero
- u8[]; // always ends in a zero byte; suitable for direct passing to C string functions
-};
-```
-
-### A "german string": a very short string that can exist in a register
+## Correctness
-Length in memory is 1 byte (3 bits?) of length, then 0-7 chars; max 8 chars.
-Fits in a 64 bit register.
+### Narrow stores in the ideal evaluator
-```java
-struct gstr { // aka germanString, or blend string and register "streg"
- u3 #; // Size is 0-7 bytes???
- u8 []; // Up to 7 bytes
-}
-// Using inlined object (see below). All these strings are short and are
-// represented as packed integers in a 64b register.
-*gstr prize1 = "gold";
-*gstr prize2 = "silver";
-*gstr prize3 = "bronze";
+Chapter 23's `Eval2.store` stores the raw value in its Java object array,
+without the truncation performed by a machine Store. This example still
+returns 25710 in the evaluator instead of 110:
+```simple
+struct C { u8 x=255; val next_noInline={ -> x++; return x; }; };
+var c=new C;
+val a=c.next_noInline();
+val b=c.next_noInline();
+return a+10*b+100*c.x;
```
-### Main becomes `val main = { str[] args -> ...}`
-
-
-## Structs can be inlined
-
-Structs are normally by-reference, but can be converted to by-value by using
-the `*` operator, pronounced "contents of" (this name might be changed to
-e.g. `inline`).
-
-This is a name-space change only, you cannot take the address of the internal
-struct without entirely consuming its lifetime. No "escaping".
-
-```java
-// 2 64-bit words, no other overheads
-struct Complex { f64 x,y; val len = { ->Math.sqrt(x*x+y*y); }; };
-
-// Current Simple rules: always by-reference
-struct ByRef {
- !Complex !c; // 4-byte pointer to a Complex
-};
-print(new ByRef.c.y); // Lookup requires 1 extra memory load from ref to c
-
-// New behavior: by value (inlining a struct)
-// The '*' syntax indicator can be something else, e.g. a keyword "inline"
-// I am pronouncing '*' as "contents of"
-struct ByValue {
- *!Complex !c; // c is inlined, full 16 bytes into ByValue
-};
-print(new ByValue.c.y); // x,y inlined into ByValue, no extra memory load
-
-// Mixing Refs and Struct Values. Basically, a ref can be converted
-// to a value by taking the "contents of" the ref, and values cannot
-// be *converted* to a ref, although they can be copied over a ref.
-ref. c = val.c; // Error, mixing refs and values
-ref.*c = val.c; // Allowed, whole structure copy. Does not allocate, requires ref.c not-null
-val. c = ref.c; // Error, mixing refs and values
-val. c = *ref.c; // Allowed, whole structure copy
-ref. c = ref.c; // Allowed, pointer copy
-val. c = val.c; // Allowed, whole structure copy.
-val *c = val.c; // Error, cannot take "contents of" a value
-
-// Alternative syntax, to avoid the "contents of" being on LHS and field applying to being on RHS:
-ref.c = val.*c; // Assign into ref.c the "contents of" val.c
-
-// Arrays of inlined structures
-var ary = new *Complex[99]; // Array of 99 !Complex !objects, inlined
-
-// Calling methods has the same syntax
-ref.c.len();
-val.c.len();
-
-// Function arguments use the same typing, so can pass-by-value
-val math.sin = { *Complex c -> ... }; // Passes a complex by value
-math.sin(ref.*c); // Requires de-reference to pass by value
-math.sin(val. c); // Pass by value
-
-```
-
-
-
-## RoadMap for other chapters
-
-`&&` and `||`
-Drop `int` to `i32`.
-Drop `TypeMemPtr` to 4 bytes; using `mmap` to make heap in low 4G.
-Default parser for-loop construction, or partial peel.
- `for( init; test; next ) body`
-becomes:
-```java
-{ init; // Normal scope entry to bound lifetime of index variable
-if( !test ) { // Zero-trip count test
- do {
- body;
- next;
- } while( test ); // Exit test at loop bottom by default
-} };
-```
-
-## `&&` and `||`
-
-The logical operators && (AND) and || (OR) are short-circuiting, meaning they may skip evaluating the second condition if the first one already determines the result:
+Find the earliest affected evaluator, reproduce the failure there, and carry
+the correction through affected snapshots. Check signed fields and floating
+rounding as well as unsigned bytes. Generated code must not be changed to
+match an incorrect evaluator.
+
+## Compilation and optimization
+
+### Reliable incremental builds
+
+`CompUnit` checks source and dependency-object timestamps when a unit is
+discovered. It can accept A's saved IR before discovering that B, whose body
+was inlined into A, needs rebuilding. An unchanged public signature does not
+make A current: optimization imports bodies and constants too.
+
+Discover the dependency graph and propagate rebuild decisions to a fixed
+point before accepting saved IR. Handle cycles together, bundled source units,
+missing inputs, and objects resolved through library search paths. Record
+compiler/serialization versions, target, ABI, and relevant options; content
+hashes can cover preserved timestamps. Distinguish rebuildable source from
+incompatible source-free libraries.
+
+An unchanged build should do no compilation or linking. Publish outputs only
+after successful compilation, and relink when an object or other link input
+changes. Start with a small build driver and conservative rebuilding of every
+dependent; finer interface/body fingerprints can follow. The
+[incremental-build design](../skills/incremental-builds.md) records the input
+ownership rules and validation cases.
+
+### Selective loading of library IR
+
+Importing `sys.io.p` currently loads all ten units bundled in `sys.o`.
+Independent, unrelated objects can remain unloaded, but selecting an object
+reconstructs all its saved IR and follows its recorded dependencies.
+
+Design member-level IR loading and dependency discovery together. Splitting
+objects alone is insufficient while reexports and unused function bodies
+still pull in their dependencies. Preserve type identity, initialization rules,
+and imported escape summaries. Loading, initializing, and emitting a class
+are separate decisions. This optimization is independent of making
+incremental rebuilding correct.
+
+### Deterministic inlining
+
+The current inliner has a bounded exception for small initializer boilerplate,
+but still uses parse-size estimates and worklist order. After shrinking
+rewrites converge, choose one growing inline using current body sizes and a
+deterministic ranking. Cache sizes per convergence round and use stable
+call-site provenance to break ties, rather than newly allocated node IDs.
+Avoid repeated whole-body scans and per-node dependencies while a large
+function gradually shrinks.
-- `&&` stops if the first operand is false.
-- `||` stops if the first operand is true.
-
-They are syntactic sugar—used for cleaner control flow—but they don't create new nodes in the execution model.
-
-The `&&` and `||` constructs are simple syntactic sugars that only modify the control flow and do not
-introduce new nodes.
-
-Consider this example:
-```java
-int a = 1;
-int b = 0;
+### CFG frequency estimates
-if(a++ || b++ ) {
- if(b == 0 && a == 2) {
- sys.io.p("Or");
- }
-} else{
- sys.io.p("And");
-}
-return 0;
-```
-- `a++` evaluates to 1 (true), so `b++` is not evaluated.
-- As a result, `b` stays 0, `a` becomes 2, and "Or" is printed.
+After lowering and loop-tree construction, estimate block frequencies for GCM
+and code layout. Treat initialization and known-failure paths as rare; use
+bounded loop-trip estimates and branch probabilities when no profile is
+available. Keep estimates consistent with control flow and shared between
+scheduling and layout. These are backend estimates, not ideal-IR types.
-```java
-int a = 1;
-int b = 1;
+### Loop rotation
-int x=1;
-int y=1;
-int z=0;
+Consider lowering `for` loops with a zero-trip entry test and a bottom-tested
+loop, or adding partial peeling. Preserve condition side effects, loop-local
+scope, and the destinations of `break` and `continue`. The current parser
+constructs a loop with its test at the head.
-int g = x++ && y++ && z++;
-...
-```
-Here:
-- `x++` is true (1), so it evaluates `y++`, which is also true.
-- Then it evaluates `z++`, which is false (0).
-- Since `&&` requires all conditions to be true, the final result `g` is 0.
-- All operands up to the false one are evaluated, so `x`, `y`, and `z` are all incremented.
+### Constant instance-field storage
-## Class initialization and compiler follow-ups
+When a final instance field has the same constant value in every instance,
+fold accesses or store the value on the class object and omit the instance
+slot. Preserve field-access semantics and public function reachability:
+externally accessible function fields remain callable regardless of storage.
+Existing static images for class constants do not implement this general
+instance-layout optimization.
+
+## Language boundaries
+
+### Source privacy
+
+Underscores already select the public interface, but source access to another
+class's private fields is not rejected. The proposal is to enforce privacy
+starting in Chapter 28a, then preserve it across imports in 28b. This language
+change still needs review; it is not a correction to impose on earlier chapters.
+
+- A field or method beginning with `_` is accessible only from its declaring
+ class, including constructors and methods. Enclosing, nested, and sibling
+ classes gain no special access. Same-class code may access another instance.
+- A private class name is available in its declaring scope and inside the
+ class itself. Naming `App._Cache` must not grant access to `_Cache._data`.
+ Dotted lookup cannot bypass access rules, and private ancestors keep their
+ descendants out of the public interface. Distinguish naming a private class
+ from using a public value returned by a factory.
+- Reads, writes, updates, method references, type names, and class-value
+ references must follow the same rule. Preserve source owner and location
+ through unresolved receiver types, inlining, and imports. Folding away a
+ Load or an unused result must not erase an illegal source access.
+- Native declarations follow the same rules. Public wrappers may deliberately
+ expose private bindings; `sys` has no special exemption.
+
+The bundled `sys/io.smp` calls `libc._exit` directly. Keep that native binding
+private, add a public `exit` wrapper in `sys/libc.smp`, and change IO to call
+the wrapper. Bitset and array helpers access their own private fields and
+remain legal. String spill fixtures with helpers outside `_String` accessing
+`_hashCode` need explicit adaptation; do not grant file-wide access merely to
+keep those fixtures unchanged. Validate native execution and imported source
+ownership alongside the access diagnostics.
+
+### Constructor helpers and completion
+
+Local SSA field updates, including final fields, repeated assignments, and
+loops, are implemented. The remaining question is broader: should constructors
+be allowed to pass unfinished `self` to helpers that become safe after
+inlining, and should completion checks wait until SCCP?
+
+Decide those rules before changing the current parser-time completion checks
+and early-publication restrictions. Separate reading an initialized field of
+an unfinished object from exposing that object to arbitrary code. The
+construction/escape teaching boundary can then be reviewed against the chosen
+semantics.
+
+### ELF visibility and unknown callers
+
+Escape analysis tracks functions reachable by unknown callers, while the ELF
+writer exports retained named functions owned by the compilation unit. Decide
+which symbols should be public, local, or hidden across separate compilations.
+Keep source privacy, ownership for emission, and unknown-caller edges distinct;
+keeping a body for linking must not imply arbitrary callers can reach it.
+
+## Initialization and runtime
### Entry arguments
-Replace the integer initializer argument with an argument array. The selected
-entry class receives a non-null array, empty when there are no arguments;
-other class initializers receive null. Coordinate the parser, entry signature,
-runtime driver, and separately compiled interfaces.
+Replace the integer class-initializer argument with an argument array. The
+selected entry class receives a non-null array, empty when there are no
+arguments; other class initializers receive null. Coordinate the parser,
+entry signature, runtime driver, and separately compiled interfaces.
+
+The native runtime already adapts process arguments for an explicit
+`simple_main` function. That does not implement argument arrays for class
+initializers.
### Pre-initialize classes from ELF data
-Prove when a class's entire initialization can be represented by ELF static
-data and relocations, with no remaining runtime effects. Emit its initial
-contents and start its `$init` flag as true, so no initializer call is needed.
-Carry that fact through separate compilation so importing compilers can remove
-checks too. A constant field alone is not proof that the whole class can be
-pre-initialized; I/O, argument-dependent work, and other observable effects
-still require execution. Preserve any dynamic parent requirement, and do not
-let cyclic dependencies justify their own pre-initialization.
+Prove when a class's entire initialization can be represented by static data
+and relocations, without remaining runtime effects. Emit those contents and
+start its `$init` flag as true. Carry that fact through separate compilation
+so importing compilers can remove checks too.
-Mutable fields may have static initial contents without becoming constants.
-Choose read-only storage only when no runtime writes remain. Static reference
-cycles can use relocations without requiring a dynamic initialization cycle.
+Constant final fields already have static images; that alone does not prove
+the whole class can be pre-initialized. I/O and argument-dependent work still
+require execution. Preserve dynamic parent requirements, and do not let cyclic
+dependencies justify their own pre-initialization. Static reference cycles
+can use relocations without requiring a dynamic initialization cycle.
+Mutable fields may have static initial contents without becoming constants.
For a wholly immutable, pre-initialized class, eliminate the mutable `$init`
-state as well as the checks so the class image can reside in ROM. The native
-function thunks preserve static initialization of function fields.
+state as well as the checks so the class image can reside in ROM. Native
+function thunks already preserve static initialization of function fields.
### Compact code and data arenas
-Keep four-byte Simple references into bounded code and data arenas; the arenas
-need not overlap or live near zero. Choose absolute addresses versus offsets
-from an arena base when implementing placement and indirect calls. Native
-function thunks can occupy the code arena while native libraries live elsewhere.
-The current thunk implementation uses the existing low-address executable;
+Use four-byte Simple references into bounded code and data arenas. The arenas
+need not overlap or live near zero; choose absolute addresses or offsets from
+an arena base when implementing placement and indirect calls. Native function
+thunks can occupy the code arena while native libraries live elsewhere.
+Currently function pointers occupy four bytes and use low-address thunks;
ordinary data pointers still occupy eight bytes.
Give full-width native pointers separate types and foreign lifetime contracts.
-Opaque device addresses may need to be passed through without CPU dereference.
-Simple object lifetimes should be managed automatically without a GC;
-ownership, borrowing, cycles, and native retention still need design. Compact
-storage alone does not establish those rules. Preserve static class images and
-explicit native boundary conversions when choosing the arena representation.
+Opaque device addresses may need to pass through without CPU dereference.
+Automatic Simple object lifetimes without a GC still need a design for
+ownership, borrowing, cycles, and native retention. Compact storage alone
+does not establish those rules. Preserve static class images and explicit
+native boundary conversions when choosing the representation.
-### CFG frequency estimates
+## Data and library proposals
-After lowering and loop-tree construction, estimate block frequencies for GCM
-and code layout. Treat initialization and known-failure paths as rare; use
-bounded loop-trip estimates and branch probabilities when no profile is
-available. Keep estimates consistent with control flow and shared between
-scheduling and layout. These are backend estimates, not ideal-IR types.
+These are language-design alternatives. The sketches below are not executable
+examples of the current Simple grammar.
-### Constant instance-field storage
+### Structs with trailing arrays
-When a final instance field has the same constant value in every instance,
-fold accesses or store the value on the class object and omit the instance
-slot. Preserve field-access semantics and public function reachability:
-externally accessible function fields remain callable regardless of storage.
+Allow named fields followed by an array length and inline element storage:
+
+```simple
+struct vecInt {
+ u32 size; // Used elements
+ u32 #; // Capacity
+ int []; // Trailing elements in the same allocation
+};
+```
+
+The final field would be named `[]`, with an unsigned length field `#`
+immediately before it. Element types could include references to the same
+struct. Current arrays have a fixed `u32` length and a special two-field
+layout; supporting arbitrary leading fields requires parser and layout work.
+
+Consider `u8`, `u16`, `u32`, or `u64` length fields to reduce small-array
+overhead. Arrays with different length representations would be distinct
+types, with explicit conversions and capacity checks. The spelling and
+alignment rules remain to be decided.
+
+Growing such an object requires a replacement allocation. An extra level of
+indirection, as in a growable-buffer wrapper, instead preserves the wrapper's
+identity. Specify ownership before treating a growing call as consuming or
+freeing its receiver.
+
+### Array initialization
+
+Allow an element-producing function at allocation, for example
+`new u8[buffer#, { u32 idx -> buffer[idx] }]`. This would support final arrays
+and fully initialized non-null reference arrays. Define when each element is
+evaluated and when the array can be published. Existing zero-filled array
+allocation does not provide this constructor operation.
+
+### String libraries
+
+Design a family of byte-based strings with UTF-8 decoding supplied by library
+functions. Consider these distinct representations and interfaces:
+
+- A growable string with inline bytes and cached metadata, returning a
+ potentially new receiver when capacity increases.
+- An immutable string constructed all at once, with defensive copying where
+ necessary. Read-only access alone does not establish exclusive ownership.
+- A StringBuilder-style wrapper holding a replaceable pointer to its buffer.
+- Unicode decoding and iteration over the byte representation, including
+ behavior at invalid character boundaries.
+- A C-compatible string with a trailing zero and directly available length.
+- A short string packed with its length into a machine word, passed by value.
+
+Keep mutable storage private by default and specify sharing, concatenation,
+capacity growth, and native I/O contracts. Existing `sys` byte-array and
+buffer helpers are a starting point, not this complete string design.
+
+### Struct values
+
+Allow a struct to be stored inline in another object, array, or argument list
+rather than always through a reference. A proposed `*Complex` or `inline`
+spelling would place both coordinates of `struct Complex { f64 x,y; };`
+directly in the containing value.
+
+Define whole-value copying, reference-to-value conversion, and assignment
+through an existing reference. A value must not silently become a reference
+or expose an interior address with an invalid lifetime. Decide how consuming
+an enclosing object's lifetime could permit such an address. Keep method
+syntax uniform and define the calling convention for by-value arguments.
+
+### Default integer width
+
+Consider making `int` mean `i32` instead of the current `i64`. This changes
+overflow behavior, layouts, APIs, and native interfaces, so it needs a language
+decision and a deliberate compatibility boundary.
+
+### Parser Cleanup
+
+Get the Parsers' structure closer to an ideal R-D parser, and matching the
+grammer doc. Move TYPES to CodeGen, and generally restructure for readability.
+Ponder using try-w-resources to do the keep/unkeep pairing (do NOT do any
+allocation in the `try`, just bring up an object w/auto-closable which tracks
+the unkeeps) - see if that looks any cleaner. \ No newline at end of file
diff --git a/docs/stage-audit.md b/docs/stage-audit.md
deleted file mode 100644
index abf90ace..00000000
--- a/docs/stage-audit.md
+++ /dev/null
@@ -1,113 +0,0 @@
-# Chapter split cleanup audit
-
-This record distinguishes checked behavior, existing gaps, and future designs
-while retiring the old combined Chapters 24/25. The final mapping is in the
-[split record](chapter-split.md). Historical Java test names are retained as
-regression identities; they do not identify current chapter boundaries.
-
-## Corrections in this cleanup
-
-- Chained comparisons now begin in Chapter 23. The early SCCP implementations
- incorrectly compared a boolean intermediate with the third operand:
- `10 < 30 < 20` returned true. Later implementations preserved the middle
- operand but reused the first operator, making `0 < 2 <= 2` false. All current
- snapshots from 23 onward now compare adjacent values using each written
- operator. Regression cases cover both directions, strict/non-strict mixtures,
- single evaluation, side effects, short-circuiting, and mixed-direction errors.
-- Chapter 23's inherited, explicitly described fuzzer scratch contains many
- comparisons using the former left-associative grammar. It is retained as an
- ignored `testJigFuzzer`, consistent with the scratch-test policy; its mixed
- directions are no longer valid source. Later snapshots already omitted it.
-- Native-library and tuning material is preserved in [appendices](appendices/README.md),
- and the former roadmap is now [docs/roadmap.md](roadmap.md).
-- The recursive-return diagnostic already passed. It remains enabled in the
- earlier snapshots and is enabled again in 28a/28b. The mutual-recursion test had an obsolete graph-string
- expectation; it now checks its existing four execution results in 24b–28b.
- In 24a, local SCCP cannot infer the recursive return type; the same example
- checks that conservative diagnostic instead. This makes the boundary explicit.
-- Allocation/runtime measurement runs passed after the comparison correction;
- the changed spill goldens record the resulting smaller graphs. Historical
- published tables retain their original compiler labels and dates.
-
-## Prefix-update follow-up
-
-Prefix `++` and `--` now use the same name lookup as ordinary reads and postfix
-updates in Chapters 23 through 28b. A method's field goes through memory; a
-constructor-local field stays in SSA. Previously, the prefix path updated the
-field declaration's parser slot and silently lost the write. The two-call
-reproducer now returns 21 instead of 11. Narrow update results stay alive while
-Store folding drops a redundant conversion from its own input.
-
-`PrefixUpdateTest` covers increment/decrement, integer/float/byte fields,
-multiple worklist seeds, local shadowing, final-field errors, native byte
-wraparound, and module fields where supported. Existing final-constructor
-coverage includes prefix updates in loops.
-
-The focused Linux checks pass in all eight affected chapters, including native
-SystemV byte-wraparound execution and the existing final-constructor tests.
-The early final-field rejection is retained so an illegal prefix update never
-enters the optimizer as a Store; native data bindings still update their writable
-contents despite having a fixed address.
-
-The Windows full suites cover 4,169 tests plus eight fuzzer regression runs;
-shared printer and ISA checks pass. Focused reruns cover the final diagnostic
-and prefix-result lifetime adjustments. The full Chapter 27 suite was rerun
-after restricting the temporary keep to prefix results; its existing spill
-expectations remain unchanged. No allocator goldens were updated.
-
-## Implemented, with narrower limits than earlier prose suggested
-
-The constructor-loop assertion is fixed in Chapters 25–27. Load forwarding now
-waits for a stored loop Phi to acquire a type at least as precise as the Load,
-and records a dependency to retry. The reduced case needs only a conditional
-assignment in a loop; break/continue and final fields are not required.
-Regressions cover the reduced case and the original constructor loop across
-worklist seeds and execution inputs. Chapters 28a/28b already had the guard;
-the corresponding earlier-chapter probes pass in 23/24a/24b.
-
-- Separate compilation imports types and optimized IR without source parsing;
- it reruns analysis and type checking with the new callers.
-- Loading is by object and recorded dependencies, not individual used members.
- A call to `sys.io.p` loads all ten bundled sys units. Independent, unrelated
- objects can remain unloaded. Loading does not imply class initialization.
-- Timestamp checks do not yet provide a reliable incremental build system.
- The [design note](incremental-builds.md) records the missing pieces.
-- Underscores select exports in modules; source privacy checks are still a
- proposal awaiting review. Do not treat hidden exports as inaccessible source.
-- Constructor-local final fields use SSA values and exit Stores. Reads of an
- unfinished object are allowed only for initialized fields. Passing unfinished
- self to arbitrary helpers and accepting completion only after SCCP are not
- promised by the current chapter boundary.
-
-## Existing failures and deferred validation
-
-- The ideal evaluator does not truncate narrow stores in Chapter 23. A byte
- update can therefore disagree with generated code; the postfix-only
- reproducer is retained in the [queue](chapter-backports.md).
-- `testModule0` is an ignored historical incremental-build experiment. It
- assumes per-source output objects and unchanged explicit-input builds, neither
- of which matches the present compiler's contract.
-- Serialization's expensive byte-for-byte round-trip assertion remains disabled.
- Ordinary import tests do not establish that stronger property.
-- Direct probes of the remaining ignored tests found a stale forward-method
- graph expectation and a missing `progs/sieve.smp` fixture in 28b. These and
- the interactive stdin test remain ignored. Ignored Jig and
- random-fuzzer entry points are intentional scratch/long-running tools.
- Audit these separately before advertising their behavior as tested.
-
-Selective loading, full incremental builds, source privacy, compact pointers,
-argument arrays, deterministic inlining, and broader constructor rules remain
-future work. They are not prerequisites for completing the chapter numbering.
-
-## Validation
-
-The affected snapshots (23, 24a, 24b, 25, 26, 27, 28a, 28b) were checked with
-their full Make suites on Windows and Linux, plus focused reruns after updating
-test expectations. The final Windows coverage is 4,143 tests plus eight fuzzer
-regression runs, with the shared printer and ISA tests also passing. The
-native library/client cases and final Chapter 28b release build pass on both OSes.
-
-A local linear-history dry run produced all 31 tags in teaching order. The
-final source snapshot, chapter navigation, Maven module IDs, and reviewed local
-documentation links were checked. Measurement capture in 24b and dynamic
-measurements in 24b/28b pass; the historical published tables were not rewritten.