Skip to content

A comment is not a blank line — and the acceptance numbers were flattered by the drop - #2766

Merged
gHashTag merged 5 commits into
masterfrom
w699-comment-gap
Aug 28, 2026
Merged

A comment is not a blank line — and the acceptance numbers were flattered by the drop#2766
gHashTag merged 5 commits into
masterfrom
w699-comment-gap

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

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:

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, 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

before after
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.

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

gHashTag and others added 2 commits August 29, 2026 04:38
…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>
@github-actions

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-08-28 21:39:57 UTC

Summary

Status Count
Total Open PRs 8
PRs with Failing Checks 7
PRs with All Checks Green 1
READY 0
FAILING 7
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=1a86c8a2d0af != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

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>
@github-actions

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-08-28 22:19:41 UTC

Summary

Status Count
Total Open PRs 8
PRs with Failing Checks 7
PRs with All Checks Green 1
READY 0
FAILING 7
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=628395ca4abb != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

…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>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-08-28 22:32:11 UTC

Summary

Status Count
Total Open PRs 8
PRs with Failing Checks 7
PRs with All Checks Green 1
READY 0
FAILING 7
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=628395ca4abb != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@github-actions

Copy link
Copy Markdown
Contributor

📓 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>
@github-actions

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-08-28 22:44:11 UTC

Summary

Status Count
Total Open PRs 8
PRs with Failing Checks 7
PRs with All Checks Green 1
READY 0
FAILING 7
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=628395ca4abb != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@gHashTag
gHashTag merged commit 9981822 into master Aug 28, 2026
34 checks passed
gHashTag added a commit that referenced this pull request Aug 28, 2026
`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>
@gHashTag

Copy link
Copy Markdown
Owner Author

Correction: not BLOCKED — amnestied

This 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.

phase              corpus  scratch   blocked
parse                  91        0         0
parse-no-discard       87        0         0
no-vacuous-invariant    0        0        72

parse-no-discard reports 87 primary corpus failures and 0 blocked. The phase that actually sits in BLOCKED is no-vacuous-invariant, at 72.

The real mechanism is amnesty: the ledger's 178 entries are 91 parse + 87 parse-no-discard. Every spec that discards is excused by name, so the suite is green because every failure the phase can report is pre-approved. That is the design working as written — and it was blind to how much, which is a sharper finding than the one I reported.

Acted on in #2772: the amnesty now carries discard_tokens, so the 1 292 tokens this PR recovered are priced and a spec that starts throwing away more fails the ratchet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant