Computed test-cell geometry (ruling #25) + the tick drain on the test path #153

Manually merged
mdoorn merged 1 commit from feat/153-computed-test-cell-geometry-ruling-25-the-tick into master 2026-07-06 15:23:15 +02:00
Owner

Computed test-cell geometry (ruling #25) + the tick drain on the test path

Along the way:

  • test-fn(tick-drain): the test cell's size is COMPUTED, and the tick drain lands on the ckc test path

Touches 5 files: src/rust/crates/ck_codegen/src/freestanding.rs, src/rust/crates/ck_codegen/src/test_object.rs, src/rust/crates/ck_driver/tests/capability.rs, src/rust/crates/ck_lower/src/test_cell.rs, tests/capability/a_ticking_actor_in_a_test_fn_is_driven.cktest.

Computed test-cell geometry (ruling #25) + the tick drain on the test path Along the way: - test-fn(tick-drain): the test cell's size is COMPUTED, and the tick drain lands on the `ckc test` path Touches 5 files: `src/rust/crates/ck_codegen/src/freestanding.rs`, `src/rust/crates/ck_codegen/src/test_object.rs`, `src/rust/crates/ck_driver/tests/capability.rs`, `src/rust/crates/ck_lower/src/test_cell.rs`, `tests/capability/a_ticking_actor_in_a_test_fn_is_driven.cktest`.
mdoorn approved these changes 2026-07-06 13:46:48 +02:00
mdoorn left a comment

Approving. I would have split src/rust/crates/ck_codegen/src/freestanding.rs differently, but not enough to hold this up.

Approving. I would have split `src/rust/crates/ck_codegen/src/freestanding.rs` differently, but not enough to hold this up.
@ -189,0 +193,4 @@
/// special binary: an actor started from a `test fn` registers its tick in the
/// same `TickSites`, and the ONE recurrence drains it here — never a second,
/// test-only drive.
pub(super) fn define_entry(
Owner

define_entry reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?

`define_entry` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?
Author
Owner

Split. The decision in define_entry is a pure function now, with its own tests in src/rust/crates/ck_codegen/src/freestanding.rs.

Split. The decision in `define_entry` is a pure function now, with its own tests in `src/rust/crates/ck_codegen/src/freestanding.rs`.
Two halves, in the order the ruling requires: re-cut the cell law, then
re-land the drive it was blocking.

THE CELL LAW (owner ruling #25). Each field of `ck_test_cell` holds a
whole `Region` — a two-word plex `{ offset, size }` — because a store
takes all of a value or refuses it (fit-or-error, docs/values.md), and
narrowing a `Region` to its base word was rejected outright: E0743's
one-word answer governs the machine LEAVES, and a `Region` is not a
leaf. So the geometry is now the ordinary Σ law every record obeys —
field sizes summed, each field the sum of ITS fields, bottoming out at
`ck_lower::layout::WORD_BYTES`. `SIZE` and `ENTRIES` are read off a
`FIELD_BYTES` array; no literal 32 and no literal 16 is asserted
anywhere, per the ruling's "the Rust derives the number from the fields
it writes, it does not assert it".

The old `SIZE = 16` was wrong twice over, exactly as the ruling says:
wrong in value (it described two BASE WORDS, not two `Region`s, so
arming the second field wrote its size word one word PAST the cell) and
wrong in kind (hand-asserted where a computed size belongs). `ENTRIES`
moves 8 -> 16 as a consequence; the cell is 32 bytes in the emitted
object.

DET-4: the derivation is the sanctioned interim, not the destination —
the module header points at plan_sizes Stage 3, where the geometry comes
from the compiler's own computed layout and these constants die into it.
`ck_lower::arena_cell` still spells its one-Region footprint as a
literal; the comment names it as the other half that unifies there.

THE DRIVE. `test_object.rs` now threads a real `tick::TickSites` through
both the user-fn emit and the entry's `UnitMainBody`, and defines the
entry through `freestanding::define_entry` — the ONE entry shape, now
shared rather than hand-rolled a second time (that hand-rolled copy is
deleted, which is most of the -64). A suite that starts no ticking actor
gets the byte-identical single `ck_entry` it always had; one that does
keeps its body as the local `ck_main_body` and gets the recurrence
wrapper, exactly as a `fn main` program does. No test-only drive exists.

THE CORRUPTION IS GONE, verified on the exact adversarial layout rather
than a safe one. In the emitted test binary `ck_test_cell` sits at
0x406060 (32 bytes) and `ck_tick_table` begins at 0x406080 — still
immediately after it, the same adjacency that was lethal. Under a gdb
hardware watchpoint on the table's count word it now transitions 0 -> 1
exactly once: the true registration count for one ticking actor. Before
the fix that word read 0x1000 (4096 — the `Alloc::os_acquire(4096)`
region size, stored one word past the cell) and the first registration
took the bounded-capacity trap, SIGILL, because 4096 >= 64.

Cell added (CELL_COUNT 334 -> 335; BROKEN and UNMARKED unchanged at
39 / 149):

- a_ticking_actor_in_a_test_fn_is_driven — WORKS,
  `tests: 1 passed, 0 failed`. An actor with a receive set, spawned
  under the Supervisor from a `test fn`, self-sends in `spawn` and stops
  itself in the handler. TERMINATION is the discriminator: the recurrence
  runs in the entry shell after the whole entry body returns, so no
  assert in the body can observe the drain — but the registry empties
  only if the tick fired and dispatched, and without the drive the
  program runs forever. Three distinguishable states across this slice
  and the last: `codegen: Unsupported` (no sites), SIGILL (sites, broken
  cell), passing (both fixed).

Ruling #26 note: `entry: test` is ruled but not yet implemented, so a
test-path boundary that stops BEFORE running still cannot be pinned.
This slice needed no such cell — the ticking actor now RUNS, so a
`tests:` declaration expresses it exactly. The 3c-ii cells pinned at
`fn main` stay as they are, per the ruling.

`Test.ck`'s header prose updated to the two-`Region` law (the cell's
size is the Σ over its fields, never a hand-written footprint).

Gates: `cargo fmt --check` clean · `cargo clippy --all-targets -D
warnings` clean, 0 warnings · `cargo test --workspace` exit code 0
(captured directly, not through a pipe): 1479 passed, 0 failed, 1
ignored across 93 targets, 0 warnings · capability 2 passed / 0 failed
(335 cells reconciled). Every cargo invocation and the gdb re-check ran
through scripts/rotate-exec.sh.
mdoorn manually merged commit d83413084d into master 2026-07-06 15:23:15 +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!153
No description provided.