opening.codex:798 says this:
let (ir-raw, lower-keep-end) = deck-record (lower-chapter ...)
and the emitted zig says this:
switch (lower_chapter(ch_1, bound, cst, ...)) { .MkTup2 => ...
The deck-record is gone. Not mis-emitted -- gone. There is no
cx_deck_enter, no cx_deck_exit, and no call to the identity deck_record
function that the same file also defines and never calls.
That matters because lower-chapter opens with a deliberate unmatched
__deck-exit: it exits an extent its caller opened. With no extent, cx_nest
goes to -1, cx_deck_enter stops swapping the cursors, and every copy the
lowering compact makes lands in the bivy that __heap-restore is about to
reclaim. One missing bracket disables the deck for the rest of the run.
The interception works 1,267 times in the same file. It misses once. The question is which layer loses it.
No. Every layer already prints, and in ASCII. The instinct to add instrumentation is the instinct that cost the most time this week, and it is not needed here:
| layer | ASCII we already have |
|---|---|
| source | the .codex file |
| AST | rust arm: parsedump, desugardump |
| checked | rust arm: checkdump |
| IR | the seed's own IR-UNI mode; rust arm's irdump |
| IR after passes | IR-UNI again, with the pipeline flag varied |
| zig | the emitted .zig |
opening.codex's dispatch names the modes outright: CDX, TEXT, IR-UNI,
IR-CCE, MEASURE, DISK, RESOLVE. We have been feeding ourselves IR-CCE all
along because that is what the transport wants, and IR-CCE is a wire format --
which is why grep deck-record on a 10 MB .ir returns zero and tells us
nothing. IR-UNI is the same content in text.
So the strategy is not "make each layer emit something". It is stop reading the compressed one.
Tonight's win was shrinking the loop from seven minutes to under two seconds. The next win is shrinking the subject from 2.6 MB of compiler to about ten lines of Codex.
The shape under suspicion is narrow:
let (a, b) = deck-record (f x)
A tuple destructuring whose scrutinee is a deck-record application. Both
sites that lose the bracket -- opening.codex:798 and :861 -- have exactly
this shape. Every one of the 1,267 sites that keeps it is, as far as we have
looked, an ordinary single-value binding.
If a ten-line chapter with that destructuring loses its bracket, the entire question collapses to one file you can read end to end, with its IR-UNI beside its zig, both short enough to eyeball. If it does not lose the bracket, then the shape is not the trigger and we have eliminated the leading theory for the price of one second.
That experiment costs less than reading the emitter does. It goes first.
usedfor can answer before we run anythingusedfor deck-record codex/ classifies every call site by what consumes it --
the tool exists, it reads the whole checkout in about three seconds, and this
is precisely the question it was built for. It answers:
deck-record calls sit in a destructuring position at allopening.codex sites are alone or the tip of a classIf the destructuring bucket has exactly two members and they are the two known sites, that is close to a proof by itself, and it arrives before any compile.
There is one question worth reading for, and it is small and named:
Does
emit-zig-applyever see this application, and if it does, why doesn == "deck-record" & list-length args == 1fail?
Three candidate answers, in the order I would test them:
emit-zig-apply. Read the match/scrutinee emitter.PIPELINE fold-constants,inline-leaf-calls,inline-single-caller on every
build. deck-record is the identity function in source -- a perfect
inline-leaf candidate. If a pass inlines it away, the name is gone before
codegen and the intercept cannot fire. Test by varying the pipeline flag,
not by reading: two IR-UNI dumps, diffed.IrName "deck-record". Renaming, cite resolution, or
the bundler's subj- prefix could make the root a different name in this
position. subj-deck-record already exists as a separate emitter rule that
emits the argument alone -- identity, no bracket -- which is the exact
failure we observe. That rule deserves a hard look regardless of what else
is true.Candidate 3 is the one I would bet on, because the identity behaviour it
implements is byte-for-byte the behaviour we are seeing, and because the
zig-skip-def comment says the intercept is obliged by skipping the def --
an obligation stated in prose is an obligation nothing checks.
fn cx_deck_exit() void {
cx_nest -= 1; // unconditional
if (cx_nest == 0) { ... }
}
A negative nest silently disables the deck. Nothing complains, nothing fails,
and the damage surfaces thousands of allocations later as a corrupt switch in
a constant folder. Refusing at nest == 0 -- panicking, loudly, naming the
caller -- converts that into a one-second failure that points at
lower_chapter. I know it does, because that is exactly what happened the
moment I added it by hand.
This is the fail-loud floor and it is worth having whether or not it is our bug, whether or not the bracket is ever restored, and whether or not anyone ever reads this paragraph. A cursor discipline that cannot detect its own violation is not a discipline.
usedfor deck-record -- three seconds, may localise it outright.cx_deck_exit refusal independently of all of it.Steps 1 through 3 cost under a minute together and will almost certainly make step 4 a five-minute read instead of a spelunk. That ordering is the whole lesson of the last two days: the measurement was always cheaper than the theory, and I kept reaching for the theory first.