Fn-main apps boot the roster — #34 closed; BROKEN ratchets 43 -> 42 #168

Manually merged
mdoorn merged 1 commit from feat/168-fn-main-apps-boot-the-roster-34-closed-broken into master 2026-07-15 08:38:28 +02:00
Owner

Fn-main apps boot the roster — #34 closed; BROKEN ratchets 43 -> 42

Along the way:

  • program(boot-entry): the shell CALLS the app's fn main, so every app shape boots

Touches 9 files: docs/actors.md, docs/modules.md, src/rust/crates/ck_driver/src/compile/mod.rs, src/rust/crates/ck_driver/tests/capability.rs, src/rust/crates/ck_load/src/desugar/boot.rs, src/rust/crates/ck_load/src/loader.rs and 3 more.

Fn-main apps boot the roster — #34 closed; BROKEN ratchets 43 -> 42 Along the way: - program(boot-entry): the shell CALLS the app's fn main, so every app shape boots Touches 9 files: `docs/actors.md`, `docs/modules.md`, `src/rust/crates/ck_driver/src/compile/mod.rs`, `src/rust/crates/ck_driver/tests/capability.rs`, `src/rust/crates/ck_load/src/desugar/boot.rs`, `src/rust/crates/ck_load/src/loader.rs` and 3 more.
Author
Owner

It is reachable. The function in src/rust/crates/ck_load/src/desugar/boot.rs returns a Result now and the caller reports it, so the unwrap on unwrap is gone.

It is reachable. The function in `src/rust/crates/ck_load/src/desugar/boot.rs` returns a Result now and the caller reports it, so the unwrap on `unwrap` is gone.
Author
Owner

Split. The decision in main is a pure function now, with its own tests in src/rust/crates/ck_load/src/loader.rs.

Split. The decision in `main` is a pure function now, with its own tests in `src/rust/crates/ck_load/src/loader.rs`.
mdoorn approved these changes 2026-07-15 08:30:00 +02:00
mdoorn left a comment

Reads well. One question on src/rust/crates/ck_load/src/desugar/boot.rs, nothing blocking.

Reads well. One question on `src/rust/crates/ck_load/src/desugar/boot.rs`, nothing blocking.
@ -276,0 +367,4 @@
&roster(&[("W::W", 2)]),
Some("App"),
)
.unwrap();
Owner

unwrap unwraps here. If this is reachable from user input it is a panic in front of a person rather than an error they can read. Is it provably there at this point, or should it carry a ??

`unwrap` unwraps here. If this is reachable from user input it is a panic in front of a person rather than an error they can read. Is it provably there at this point, or should it carry a `?`?
@ -541,0 +606,4 @@
the shell CALLS this `fn main` instead of being replaced by it (owner ruling #34: \
entry is an entry, not a topology class). A call across a module boundary reaches \
only what the callee's header declares, so the entry is public surface now. \
Declare it in `{module}.ckh`:\n\n mod {module}\n\n fn main() -> Unit\n\n\
Owner

main reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?, at src/rust/crates/ck_load/src/loader.rs:609.

`main` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?, at src/rust/crates/ck_load/src/loader.rs:609.
Closes ruling #34 (2026-08-13): "Bootstrap.ck starts them under the root
Supervisor before entry, for EVERY app shape; entry (fn main or actor
topology) is an entry, not a topology class."

THE DEFECT. Entry selection made the two shapes mutually exclusive arms of one
`or_else`: the app's own `fn main` did not merely win, it REPLACED the shell.
So a `fn main` app had no boot phase to hang a declared instance on and
silently ignored its whole roster — it linked, ran and exited 0 while doing
none of what Program.ck declared.

THE MECHANISM is the one the ruling names: the app's `fn main` becomes
something the shell CALLS rather than something that replaces it. `BootEntry.ck`
is that shell — Supervisor, boot, hand-off — the twin of `Bootstrap.ck`, which
stays byte-for-byte as it was. They differ only in the tail: no entry actor
here, so no `Meta::spawned`/`despawned` lifecycle to frame. `Program::entry()`
is the hand-off site, expanded to a plain `Mod::main()` naming whichever app
module declares the entry. Both sites self-delete when they have nothing to
say, so the shell compiles in the stdlib-only closure too.

A SHRINK ALONG THE WAY. The boot expansion moved from two places — an ingest
hook plus a backward `re_expand_boot` over a cached stdlib — to ONE pass in
`finish()`, where the whole closure is loaded and both facts (the roster, and
whether the app has its own `fn main`) are in hand. There is no point during
the walk at which a shell page and the facts configuring it are both
available; after the walk, both always are. The resumed load gets correctness
for free instead of needing its own pass.

E0608. The shell calls the app's entry ACROSS A MODULE BOUNDARY, so the entry
is public surface and the two-file law applies to it like any other
cross-module fn: its header must declare it. Checked, not synthesized — a
header the compiler wrote would be public API the author never declared, the
two-file law routed around by the one component it exists to constrain.
Without the check this reached codegen as `unsupported Floor IR form` against
a span in the SHELL, naming neither the app nor the fix. (#34's "the author
spells nothing" is not contradicted: that clause is about the
instance-to-effect BINDING, #31, not module visibility.)

OPT-IN, UNCHANGED AND PROVEN. The new shell is selected only when the roster
is non-empty AND the app has its own `fn main`; without a roster the app's
`fn main` still wins outright. All 37 committed sizes pins unmoved
(`--test sizes_pin`, exit 0). Four combinations probed end to end: fn-main +
roster boots then enters; fn-main without a roster is untouched; actor app +
roster unchanged; unexported entry is E0608.

Main::Main NOT deleted, and deliberately. The entry unification does not make
it deletable — it makes it MOVABLE, from CkLang into a Rust string literal,
because byte-identity for roster-free actor apps requires emitting exactly
today's `Spawn::spawn::<Main::Main>(sup)`. Moving a name out of CkLang into
the compiler is the wrong direction (CLAUDE.md §2), so the line stays authored
in Bootstrap.ck. Making the entry actor roster-driven would need new roster
surface, which #33 excluded ("instance counts and NOTHING speculative").

Cells 357 -> 358: `program_boot_does_not_reach_a_fn_main_entry` is REPLACED by
`program_boot_reaches_a_fn_main_entry` (the same position, the law now
holding), plus `program_fn_main_entry_is_not_exported`.
BROKEN_CELL_COUNT 43 -> 42 — the ratchet tightens. UNMARKED unchanged at 149.
mdoorn manually merged commit 5a1921f4d0 into master 2026-07-15 08:38:28 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
northgale/cklang-bootstrap!168
No description provided.