A comment is not a blank line — and the acceptance numbers were flattered by the drop - #2766
Conversation
…tement
87 specs silently discard 33,777 top-level tokens. The discarded content is the
BODIES of invariants and tests -- the asserts vanish and the phase that would
notice sits in the suite's BLOCKED column, so nothing reports it. Two causes,
found by bisecting one spec down to nine lines each.
1. A COMMENT READ AS A GAP
The braceless-block boundary asks whether a statement is adjacent to the
previous one, and asked it as `line <= last_line + 1`. A comment line
therefore counted as a gap:
invariant has_comment
// a comment between the header and the body
const a = f(1); <- discarded
The rule is about a BLANK line -- the comment beside it says "a blank line
before the const meant module scope to every reader" -- and a comment is not
blank. A reader sees it as part of the block.
discarded tokens: 33,777 -> 32,728 (-1,049)
2. `then` COULD NOT TAKE A STATEMENT
`then` parsed its body with `parse_expr`, and specs write
then for (i in 0..100) { assert t1 == -t2; }
`parse_expr` cannot read a `for`, the clause returned false, and the whole
block fell to the discard -- taking the asserts INSIDE the loop with it.
`then <expr>` alone always worked, which is why this survived.
No corpus movement: the shape is rarer than the census suggested. It is here
because the parser now accepts a form it rejected, with a conformance case
that fails when either fix is reverted.
THE ACCEPTANCE COLUMNS WENT DOWN, AND THAT IS THE POINT
Zig accepts it 217 -> 215
cc accepts it 157 -> 156
ALL FOUR 63 -> 62
Isolated to fix 1 by building it alone. Recovered invariant bodies generate code
that three specs' backends cannot compile -- which means those specs were being
accepted on LESS CODE THAN THEY CONTAIN. The number was flattered by the
discard. Naming the three is follow-up work; the local zig harness I tried
reported an implausible zero and was not trusted.
Suite 2424 passed / 0 failed, ratchet clean, seal gate 0.
Refs #2754
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-146) Recovering 1049 discarded tokens moved Zig 217->215 and cc 157->156. Those specs were accepted while their assertions vanished; the number was measuring the drop. Reverting to restore the pretty figure would be the real regression. Bisect to a file you can hold in your head -- and copy the corpus's shape rather than inventing one: my first minimal case used a form the corpus does not contain and failed to reproduce. And never delete lines by matching a debug word: removing my probes also removed a pre-existing format! argument for a variable named probe_idx. Refs #2754 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
emit-bitexact caught this on the previous commit: compiler/codegen/testgen.t27
stopped generating with any backend.
const backends = [_][]const u8{ "zig", "c" };
`parse_expr` reads `[_][]`, stops on the `const` INSIDE the type, and the
statement was minted as CLEAN because `is_block_boundary(KwConst)` is true. The
parser was standing mid-type. The next turn read `const u8{` as a second
statement, failed, restored and broke -- and because one statement had already
lowered, the whole-block fallback at the end never fired, so the wreckage was
handed to module level, where a const is a HARD error.
The disjunct contradicted the rule stated four lines above it: "Clean means
current OPENS its line." A boundary keyword mid-line is somebody's type. Removed.
This defect is OLDER than the comment fix -- a spec with the same const on the
line directly after the header fails on master too. The comment fix only widened
the set of specs that reach the arm. Both repros are now clean.
parse-complete 87 specs / 32728 discarded tokens -- unchanged
corpus Zig 215, rustc 214, cc 156, iverilog 373, ALL FOUR 62
-- unchanged, so the repair costs nothing
check_specs_generate.py OK: 716 specs, 613 generate, 103 ledgered
suite --ratchet --corpus-only RATCHET: CLEAN, exit 0
cargo test --no-fail-fast 2424 passed, 0 failed
parse-conform case `array_type_const_is_not_a_boundary` added and verified
load-bearing: restoring the disjunct fails it (18 -> 17 passing).
Refs #2754
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-08-28 22:19:41 UTC
Summary
Seal Status
|
…neration The seal gate's own warning, applied to me: "t27c seal --save will still seal it with gen_hash=none." Commit 3cff748 broke testgen.t27's generation and then wrote gen_hash_{zig,c,verilog,rust}=none into .trinity/seals/testgen.json in the same commit -- recording the breakage as the reproducible truth. Two gates caught it (emit-bitexact, coverage/gen-drift); I did not. Now that generation is restored, both seals carry real hashes again. Zig and C moved (the invariant body lowers now); Rust and Verilog are byte-identical to 2026-08-28T20:32Z, before any of this branch's parser work. Also visible here and NOT fixed: this spec has TWO seals, testgen.json (module name) and codegen_testgen.json (path-derived), and `seal --save` writes only the second. The first will drift again the next time the spec's output changes. check_seal_coverage.py OK: 1316 seals, 1222 hold, 94 ledgered, exit 0 Refs #2754 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR DashboardGenerated at: 2026-08-28 22:32:11 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
The binary the gate runs is not the binary you rebuilt. The gate's own warning text can be a description of your last commit. And a spec with two seals takes two repairs. Refs #2754 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-08-28 22:44:11 UTC
Summary
Seal Status
|
`t27c seal <spec> --save` writes a path-derived file name. Many specs also carry
an older seal keyed by the bare module name, both naming the same `spec_path`,
and the gate reads both while --save updates one.
seals with a spec_path 1311
specs sealed more than once 547
of those, pairs that DISAGREE 31
The failure is quiet: on #2766 a spec was repaired, re-sealed, and `coverage`
stayed red -- on the twin. This command names those pairs in one call.
It reports and does not write. Which of two disagreeing seals is the truth is
#2767's decision; re-sealing both would freeze whichever generation happens to
be current into two places instead of one.
Two tests, each for a way the comparison could be wrong: a difference in ANY of
the five fields counts (testgen's twin matched on rust and verilog and differed
on zig and c -- a single-hash comparison would have called it identical), and an
absent field is not equal to a present one.
A missing .trinity/seals is an error, not "zero twins": nothing was read, so
nothing is claimed.
Refs #2767
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Correction: not BLOCKED — amnestiedThis PR's body says "the phase that would notice sits in the suite's BLOCKED column, so nothing reports it." That is wrong, and I repeated it in the commit message and on the loop dashboard before checking.
The real mechanism is amnesty: the ledger's 178 entries are 91 Acted on in #2772: the amnesty now carries |
Refs #2754
87 specs silently discard 33,777 top-level tokens. The discarded content is the bodies of invariants and tests — the assertions vanish, and the phase that would notice sits in the suite's BLOCKED column, so nothing reports it. Two causes, each bisected down to nine lines.
1. A comment read as a gap
The braceless-block boundary asks whether a statement is adjacent to the previous one, and asked it as
line <= last_line + 1. A comment line therefore counted as a gap:The rule is about a blank line — the comment beside it says "a blank line before the const meant module scope to every reader" — and a comment is not blank. A reader sees it as part of the block.
2.
thencould not take a statementthenparsed its body withparse_expr, and specs writeparse_exprcannot read afor, so the clause returned false and the whole block fell to the discard — taking the asserts inside the loop with it.then <expr>alone always worked, which is why this survived.No corpus movement: the shape is rarer than the census suggested. It is here because the parser now accepts a form it rejected, with a conformance case that fails when either fix is reverted.
The acceptance columns went down, and that is the point
Isolated to fix 1 by building it alone. Recovered invariant bodies generate code that three specs' backends cannot compile — which means those specs were being accepted on less code than they contain. The number was flattered by the discard.
Reverting to restore the prettier figure would be the actual regression. Naming the three specs is follow-up work: the local zig harness I tried reported an implausible zero and was not trusted.
Suite 2424 passed / 0 failed, ratchet clean, seal gate 0. Two conformance cases added, both verified load-bearing by reverting the fix they cover.
🤖 Generated with Claude Code