capability: the script gate learns the sixth stage the merge just added #226
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/226-capability-the-script-gate-learns-the-sixth-st"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
capability: the script gate learns the sixth stage the merge just added
Along the way:
scripts/test.sh, and it is invoked directlyTouches 91 files:
.claude/commands/next-broken.md,CLAUDE.md,docs/01-laws.md,docs/02-programs.md,docs/03-types.md,docs/04-bindings.mdand 85 more.Split. The decision in
resolve_install_idis a pure function now, with its own tests insrc/rust/crates/ck_codegen/src/freestanding.rs.Measured. It is a named constant in
src/rust/crates/ck_driver/tests/capability.rsnow, with a line saying how, at src/rust/crates/ck_driver/tests/capability.rs:531.Comment added on this line in
src/rust/crates/ck_driver/src/lib.rs. It was obvious when I wrote it and it will not be in a month.Reads well. One question on
src/rust/crates/ck_codegen/src/freestanding.rs, nothing blocking.@ -167,3 +167,3 @@/// emitted user fns' Cranelift ids: the driver lowered `Arena::install` as an/// ordinary user fn, so its absence here is a backend invariant break.fn resolve_install_id(pub(super) fn resolve_install_id(resolve_install_idreads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?@ -718,0 +721,4 @@// `MonoError::kind`, never on the rendered message, like its siblings.compile::CompileError::Monomorphize(e) => {Ok(ck_cktest::Capability::Monomorphize(e.kind().to_owned()))}I had to read this line twice. Nothing wrong with it, but one line of comment would save the next person the second read, at src/rust/crates/ck_driver/src/lib.rs:724.
@ -502,0 +528,4 @@// boundary for every raise kind rather than only the ones the pass already// checked in-block. The may-raise seed is deliberately NOT widened: doing so// would re-mask the mis-ordered emit exactly as `Panic::raise` did.const BROKEN_CELL_COUNT: usize = 44;Where does the number beside
BROKEN_CELL_COUNTcome from? It reads as measured rather than chosen, and nothing on the line says which, at src/rust/crates/ck_driver/tests/capability.rs:531.`a_list_literal_in_a_test_fn_body_fails_the_suite` is fixed and renamed to `a_list_literal_in_a_test_fn_body_runs`. BROKEN_CELL_COUNT 46 -> 45; CELL_COUNT holds at 440 (a rename). The bug was one word of reasoning, written down and then trusted for a year of commits: the test path passed `None` for the entry's arena-install fn because "the test path retargets allocations in the codegen tier (`alloc_target`) rather than through an entry prologue". That is true of WHERE an allocation goes — the retarget routes it to the CkLang `Arena::alloc` — and says nothing about whether the arena EXISTS. `Arena::install` (`Arena.ck:35`) is what writes cursor 16 and capacity 65536 into the region header. Without it `alloc` read a zero header, `cursor + bytes > capacity` was `0 + n > 0`, and the bump raised `OutOfMemory::Exhausted`. Every allocating `test fn` failed, whatever it allocated and whether or not it ever read it back. Two halves of one pair, and only one was lowered into the test object: `compile::testfloor::floor_targets` extended its target set with `a.alloc` alone, so `Arena::install` had no emitted body for the entry to call even if the entry had asked. Both now reach the object, `FreestandingTestEntry` carries `install` beside `alloc`, and `define_freestanding_entry` resolves it through `freestanding::resolve_install_id` — the same function the `fn main` path uses, widened to `pub(super)` rather than copied. Nothing in the list tier moved. The cell had said so from the day it was written ("the fix is in whatever the test entry hands a body as its allocation target, not in the list tier"), and it was right. Measured beyond the matrix: `ckc test tests/corpus_test_run/lists` now reports `2 passed; 0 failed`, where the cell recorded both as failing. That app was green throughout on `corpus_test_run`, whose `run.md` grammar has no `tests:` verb and reconciles `exit:` only — the hole is named in plan.md §4c and stays open. Gates: three legs green (unit 1354, corpus 106 apps, capability 440 cells), fmt clean, clippy 0 warnings. `architecture::r3_no_file_exceeds_loc_cap` is red and was red before this commit (`ck_driver/src/lib.rs` 1322 lines, cap 862, verified against the unmodified tree); this commit is net-zero on that file.`a_loop_bound_raise_in_the_entry_tail_is_swallowed` → `..._is_reported`. BROKEN_CELL_COUNT 45 → 44; CELL_COUNT holds at 440 (a rename). The wrong reasoning, in one sentence: `ck_codegen::cfg::emit_return` read "the boundary checks the raise cell before its normal return" as "before the return is EMITTED", and put the check at the top of the function — ahead of the `match mode` that emits the tail expression. The mechanism, as instruction order. For the entry's `Return(Some(call overrun))` the emit was load tag ; 0 — nothing has raised yet brif tag, crash, cont cont: call overrun ; stores tag = 1, returns the propagation dummy return dummy ; the dummy IS the exit code so `fn main() -> Int { overrun() }` exited 0 where the law says 101. Two things hid it. `let n = overrun(); n` escapes because the call is a Floor STATEMENT, emitted ahead of the terminator, so the load already saw tag = 1 — that is the twin cell, `a_loop_bound_raise_in_a_let_slot_is_reported`, and the pair is what localised the defect in the SLOT rather than in `while<N>`. A `Panic::raise` tail escapes for the other reason: `raise_lower::lower_tail` binds a sanctioned may-raise call to a temp and emits its own in-block check — but the may-raise fn set is seeded only from `Panic::raise` op references (`ck_driver::compile::raise::closure_may_raise`), so a `while<N>` bound raise seeds nothing, gets no in-block check, and rode the tail slot out. What moved: the check now sits at each `ReturnMode`'s own return site, after the tail has been evaluated — all four modes, including both return sites of `emit_value_words_return`. The crash block already ends in a `return_`, and `cont`'s only predecessor is the block the tail value was defined in, so dominance holds and `seal_all_blocks` is unaffected. The doc comment that stated the wrong reasoning now states why it was wrong. What deliberately did NOT move: the may-raise seed. Widening it to cover loop-bound raises would give `overrun` an in-block check and turn this cell green while leaving the boundary emit mis-ordered — re-masking the defect exactly as `Panic::raise` did. `plan_call_stack` §2.2 needs the branch to exist AT the entry, which is now true for every raise kind. Gates, all under the shared rotating mask: ./scripts/test-capability.sh -v <cell> <twin> — cell self-retired printing `runs: 101`, which is the proof the fix landed ./scripts/test.sh — ALL GREEN, 3 legs: unit 1354 passed / 0 ignored, corpus 106 apps, capability 440 cells cargo test --workspace --tests --no-fail-fast — 1610 passed, 1 target failed: `-p ck_driver --test architecture`, `r3_no_file_exceeds_loc_cap` on `crates/ck_driver/src/lib.rs: 1322 lines (cap 862)`. PRE-EXISTING and not this commit's: verified by `git stash` on the unmodified tree — identical failure, identical 1322 lines. No file this commit touches is at or near its cap (`ck_codegen` cap 594, `cfg.rs` 331; fn cap 72, `emit_return` 68). cargo fmt --all -- --check — 0 cargo clippy --workspace --all-targets -D warnings — 0 Law 3 sweep on the old cell name: three prose claims cited the swallow — the twin cell's "the program then exits 0" pair table, `untrapped_raise_reports_no_call_stack`'s "not hypothetical" bullet, and the twin's STATUS line. All three rewritten to say what is true now and to keep the mechanism as history. `plan.md` §1 ledger and §4c updated.scripts/test.sh, and it is invoked directly 3d8a3a3be0`docs/` was deleted in 07a49fef because it could never go green, and §6 has said since that it "exists in NEITHER repo". That sentence is now false, so it is corrected rather than left standing — a false claim about where the truth lives is the defect that section is about. What lands is a 16-chapter book plus its gate. The condition is the whole point: every DELIVERED claim is a runnable project under `docs/examples/` paired with the outcome it must produce, and `scripts/test-docs.sh` is a leg of `scripts/test.sh`, so a chapter stating something the compiler does not do turns the gate RED. 19 fixtures, 35 expectations. The old `docs/` made claims no machine read; this one cannot. Strict in BOTH directions, like the capability matrix: `for_does_not_lower` pins a DESIGNED gap and fails when that gap CLOSES, because the chapter documenting it is then wrong. A behavioural sentence carries DELIVERED or DESIGNED, or it is a defect in the book. WRITTEN AGAINST THE SIBLING'S STDLIB FIRST, WHICH IS WHY THE GATE EARNED ITS KEEP ON THE FIRST HONEST RUN. Re-pointing at this repo's oracle broke four expectations, and every one was a real defect: · effect rows were missing from the book entirely — the cells carry `effect Assert` and the transcription dropped it. E0413 now has a chapter section (ch.10) and a fixture; ch.5/8/12 corrected; · ch.3 claimed `Collection::len` does not lower. Against this oracle it runs — it is a TRAIT method, and `List::len` is E0301; · ch.13 described the sibling's 20-unit stdlib, not this repo's 38-unit oracle. It now sets out both, measured: `Floor.ckh` byte-identical, `Types.ck` 618 vs 158, `Prelude.ck` 769 vs 488, `Alloc`/`Arena` here and excised there; · paths cited `tests/gaps/`, which no checkout here contains. Bare paths are this repo now; `CkLang:` prefixes the sibling — the same rule §6 already stated for doc comments. The book is gated against THIS repo's compiler and THIS repo's oracle. A cross-repo `--stdlib` would make a green here a statement about a checkout nobody in this repo controls.