grammar: the header table follows the corpus, not the other way round #224

Manually merged
tvidal merged 5 commits from feat/224-grammar-the-header-table-follows-the-corpus-no into master 2026-09-08 15:27:00 +02:00
Owner

grammar: the header table follows the corpus, not the other way round

Along the way:

  • plan: the ledger says what the tree says, and the gate debt is discharged
  • plan: 4a is a law, 4c is measured, and the constraint was the defect
  • plan: the unmerged branch, and six open items the gate run exposed
  • gates: the oracles become scripts — three legs, two compiler verbs, no wrappers

Touches 10 files: CLAUDE.md, cpu_broken.md, plan.md, scripts/lib/rotate-cpus.sh, scripts/test-capability.sh, scripts/test-corpus-test-run.sh and 4 more.

grammar: the header table follows the corpus, not the other way round Along the way: - plan: the ledger says what the tree says, and the gate debt is discharged - plan: 4a is a law, 4c is measured, and the constraint was the defect - plan: the unmerged branch, and six open items the gate run exposed - gates: the oracles become scripts — three legs, two compiler verbs, no wrappers Touches 10 files: `CLAUDE.md`, `cpu_broken.md`, `plan.md`, `scripts/lib/rotate-cpus.sh`, `scripts/test-capability.sh`, `scripts/test-corpus-test-run.sh` and 4 more.
tvidal approved these changes 2026-09-08 10:52:23 +02:00
tvidal left a comment

A clear improvement. The change in src/rust/crates/ck_driver/tests/corpus_run.rs is the part I would have argued for.

A clear improvement. The change in `src/rust/crates/ck_driver/tests/corpus_run.rs` is the part I would have argued for.
@ -377,0 +514,4 @@
/// optional `--stdlib <path>` (used only for a directory), and `--opt
/// <none|speed>`. A second positional, an unknown flag, an unknown `--opt`
/// value, or a missing path is an error.
fn parse_build_args(args: &[String]) -> Result<BuildArgs, String> {
Owner

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

`parse_build_args` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?
@ -157,0 +218,4 @@
let linked = matches!(self.built, Built::Linked);
let (exit, stdout, stderr) = match &self.built {
Built::NotAttempted => return Some(format!("`{app}`: nothing was attempted")),
Built::Refused { rendered } => (1, String::new(), rendered.clone()),
Owner

Built is cloned on what looks like a hot path. Is the ownership forced here, or can this borrow?

`Built` is cloned on what looks like a hot path. Is the ownership forced here, or can this borrow?
Author
Owner

It can borrow. The clone of Built was left over from before the lifetime was threaded through src/rust/crates/ck_driver/tests/corpus_run.rs, and it is gone.

It can borrow. The clone of `Built` was left over from before the lifetime was threaded through `src/rust/crates/ck_driver/tests/corpus_run.rs`, and it is gone.
Author
Owner

Split. The decision in parse_build_args is a pure function now, with its own tests in src/rust/crates/ck_driver/src/lib.rs.

Split. The decision in `parse_build_args` is a pure function now, with its own tests in `src/rust/crates/ck_driver/src/lib.rs`.
`the_header_measurement_table_is_the_measurement` went red on one row of
twenty-five: M4's site read `Types.ck:468` while the run measured `:467`.
Nothing about the measurement changed — the value is still 4 fields, still
the named-tuple TYPE at `fn from_literal(g: (| lat, latd, lon, lond |))`.
The corpus moved under it when `Types.ck` lost a line above that point.

The gate is machine-produced on both sides for exactly this reason: the
header is a claim about the corpus, so when they disagree the corpus wins
and the header is the defect.
§1 carried two false numbers and one false claim. CELL_COUNT read 439 and
BROKEN_CELL_COUNT 54; the tree measures 440 and 47 — each worktree knew only
its own delta, and the merge is where they compose. Measured, not summed.

The false claim was "one target has not been re-run since the fix". It has
now. `--test capability` ran on the merged tree and came back RED on three
cells of 440, which §1 should say plainly rather than keep describing a debt
that is paid. None of the three is a regression on correct code: one moved
forward, one stopped at a stage the matrix has no verb for, and one is the
bug its own cell documents being fixed under a diagnostic that explains a
tag-slot refusal in terms of numbers.

The five `money_*` cells §6 feared for were already green at b5668540 and had
simply never been observed — the constraint's cost, now a number.
Three sections were stale in different ways, and the third is the one worth
reading.

§4a described "the monomorphised size table" and treated the size walk's
declaration-pricing as orthogonal to the coherence table. Both readings are
retired by owner ruling: size is carried by the representation, every type has
a row, and `String<64>` is not `String<128>`. Investigation agreed with all
three — monomorphisation covers generic fns only (mono.rs:316), impls and
records and data are unstamped (maps.rs:216,236), and the key's size wildcarding
is the workaround for the impl stamp that was never minted. One defect, three
faces: the key, the size walk, and frame_layout's discarded slots, each of them
a number computed and thrown away. Slices 1-3 landed; slice 4 is next and is
confirmed implementable.

§4c counted 54 BROKEN cells in clusters headed by "16 codegen: Unsupported, a
third of the ledger". Measured: 47, and 11.

§5 and §6 carried the reasoning that made avoiding the gate look prudent. The
gate was slow because it ran an unoptimized compiler one cell at a time; once
that was fixed the first run found five cells that had been green and unobserved
since b5668540, a cell that had moved forward, a cell stopped at a stage the
matrix has no verb for, and a documented bug already fixed under the wrong
diagnostic. None of it was inferable. Three agents each argued inertness
correctly and the ledger was wrong regardless, because it recorded observations
nobody had made.

An unaffordable gate does not delay verification. It converts measurements into
assumptions and keeps printing them in the same font.
§0 is new and exists because `ec179d8a` is unmerged: it carries the sixth
Capability form, the E0742/E0757 split, and a ratchet move. Starting §4a or
§4c without it means re-deriving all three.

§4f gains what the run turned up and nobody had a place for: `ckc check` and
`ckc run` disagreeing with no way to pin it, `Money<3>` admitting a number
where only a variant is lawful, an unmarked broken cell held back so its
decrement stays visible, `24s` folding to 24 hours behind a codegen park, and
corpus.rs reconciling only resolution while nine of eleven traps refuse at
typecheck.
`cargo test --workspace` was the gate, and three costs were hiding in it: 57
integration binaries each statically linking the whole compiler, the same 106
corpus apps compiled twice by two of them, and 440 capability cells taking 440
container round-trips. None of it was visible, because no leg could be named or
run on its own.

Three leg scripts now exist, and `scripts/test.sh` only sequences them:

    test-unit-tests.sh        1352 unit tests + doctests          1.8s
    test-corpus-test-run.sh   106 apps, one container, one exec   3.9s
    test-capability.sh        440 cells, no container             4.7s

Every leg runs even when an earlier one is red, for the reason the old file
already gave about `--no-fail-fast`: a gate that stops at the first red reports
one failure when the truth is three, and which one you see depends on the order
they were listed in.

Two compiler verbs, because a shell oracle may compare exit codes and bytes of
machine-readable output and nothing else — if it needs a regex over a rendered
diagnostic, the CLI is missing a verb:

  * `ckc build <path> -o <out>` — compile + link, no container run. `run` did
    all three as one act, so a harness wanting N binaries in a mount could not
    ask for them. It is `disassemble` minus the objdump.
  * `ckc outcome <dir>...` — the compiler states how far it got, in the
    `# capability` vocabulary, rendered by `ck_cktest::CapabilityCell`'s own
    Display so the printed line and the declared block cannot become two
    spellings. Matched on the error VARIANT, never on prose. A stage with no
    form is an error, not a guess.

The verbs are what make these oracles outlive Rust. `capability.rs` matches on
`ck_lower::LowerError` in-process, so the matrix can only ever judge the
compiler it is compiled into — and Law 5 says that compiler is replaced. The
same 440 cells now go through the CLI, so `ckc.ck` can be held to the identical
files.

Cross-validated against the Rust harness: 437 agreements and the same 3
disagreements plan.md §1 already records (`const_generic_fn_call` forward,
`impl_method_signature_size_param` at a stage with no form,
`money_unknown_currency_tag_is_accepted` regressed). The gate is RED on those
three, which is the honest state of the tree.

Each leg's own findings, since a green that has never gone red proves nothing:
every gate was deliberately broken and observed to fail — a wrong `exit:`, a
wrong `stderr_contains:`, a flipped `// STATUS: BROKEN` (the ratchet fired), a
failing `#[test]`.

`rotate-exec.sh` and `test-rotate.sh` are DELETED. Each leg computes the shared
rotating mask itself and refuses if the degraded core is back online, so a
wrapper you must remember to invoke is a gate you can run without. CLAUDE.md
§4/§5, cpu_broken.md, plan.md §5 and the lib's own header are corrected in this
commit: a contract naming a deleted script is the Law 3 defect. One gap is now
recorded rather than created — `--serial`'s narrow mask, the mitigation for the
single-core thermal concentration, has no caller today.

The gate PRINTS what it does not cover, on every run. The legs are replacing 57
binaries one at a time; until the last lands, a green here is a green over part
of the tree, and `conformance.rs`, `corpus.rs`, `sizes_pin.rs`,
`frame_reconcile.rs` and the rest are named individually, because "and some
others" is how a coverage hole becomes permanent.
tvidal manually merged commit d6c8fb01b8 into master 2026-09-08 15:27:00 +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!224
No description provided.