Skip to content

fix(verilog): a real value must not travel in an integer container (+6 declared tests, 0 regressions) - #2991

Merged
gHashTag merged 5 commits into
masterfrom
w42-verilog-break
Aug 30, 2026
Merged

fix(verilog): a real value must not travel in an integer container (+6 declared tests, 0 regressions)#2991
gHashTag merged 5 commits into
masterfrom
w42-verilog-break

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

fix(verilog): a real value must not travel in an integer container

Two sites, one class, both found by pointing t27c icarus-simulate at a spec
for the first time -- the repository's only ruler that RUNS generated Verilog,
and one that has had zero targets since specs/scratch was untracked (#2987).

  1. gen_verilog_expr sent every * through __mul_noop, the shift-and-add
    ladder added by wave-27: t27c gen-verilog emits __mul_noop(a, b) instead of bare * (R-SI-1) #741 so synthesizable RTL carries no * operator (R-SI-1).
    The ladder is declared input [63:0], so a float operand is rounded before
    use: __mul_noop(0.3, 10.0) is 0, and ewma_step(5.0, 0.3, 10.0) returned
    5.0 where C, Rust, Zig and hand arithmetic all say 6.5. R-SI-1 governs
    SYNTHESIZABLE RTL; Verilog real is a simulation-only type no synthesis
    flow accepts, so a real multiply was never in that rule's subject.

  2. A given binding was emitted reg [63:0] e; whatever its initializer
    returned, so e = ewma_step(0.5, 0.5, 1.0) stored 1 instead of 0.75.

Measured, specs/trinet/etx.t27 under icarus-simulate:
before 5 PASSED / 6 FAILED, exit 1
after 11 PASSED, exit 0

Corpus: 46 of 581 generated .v change; iverilog -g2012 accepts 380 before and
380 after. Acceptance does not move because the ladder always produced valid
Verilog -- it computed something else. Seals for the 46 are re-sealed here, in
this commit, with that acceptance reading as the reason.

Two corrections to my own work, kept because they are the finding:

  • I predicted three tests would flip from the multiply fix alone and that the
    three alpha_* would not move. One flipped; all six moved once the binding
    was fixed too. The prediction was wrong in both directions and the two
    defects are one class at two sites.
  • The ExprLiteral arm first read extra_kind == "float" || value.contains('.').
    Nothing in this compiler ever sets extra_kind to "float" -- a condition
    invented rather than read. It is gone. The mutation that found it was itself
    broken first (false && A || B disables only the left disjunct), so the arm
    looked dead when the instrument was.

Mutation-checked, 5 of 5 killed: always-ladder, always-reg, everything-is-real,
a-call-is-never-real, a-literal-is-never-real. verilog_r_si_1.rs is the
control that the integer path is unchanged; it stays green.
rustfmt --check reports 315 complaints on compiler.rs before and 315 after.

Closes #2990
Refs #741, #2987


Found by the sweep that produced #2987, #2988, #2989 and #2990. The other three
are filed, not fixed: they need machinery this backend does not have (a named
block per loop) or a decision about 260 baselines.

🤖 Generated with Claude Code

Two sites, one class, both found by pointing `t27c icarus-simulate` at a spec
for the first time -- the repository's only ruler that RUNS generated Verilog,
and one that has had zero targets since specs/scratch was untracked (#2987).

1. `gen_verilog_expr` sent every `*` through `__mul_noop`, the shift-and-add
   ladder added by #741 so synthesizable RTL carries no `*` operator (R-SI-1).
   The ladder is declared `input [63:0]`, so a float operand is rounded before
   use: `__mul_noop(0.3, 10.0)` is 0, and `ewma_step(5.0, 0.3, 10.0)` returned
   5.0 where C, Rust, Zig and hand arithmetic all say 6.5. R-SI-1 governs
   SYNTHESIZABLE RTL; Verilog `real` is a simulation-only type no synthesis
   flow accepts, so a real multiply was never in that rule's subject.

2. A `given` binding was emitted `reg [63:0] e;` whatever its initializer
   returned, so `e = ewma_step(0.5, 0.5, 1.0)` stored 1 instead of 0.75.

Measured, `specs/trinet/etx.t27` under `icarus-simulate`:
  before  5 PASSED / 6 FAILED, exit 1
  after   11 PASSED, exit 0

Corpus: 46 of 581 generated .v change; `iverilog -g2012` accepts 380 before and
380 after. Acceptance does not move because the ladder always produced valid
Verilog -- it computed something else. Seals for the 46 are re-sealed here, in
this commit, with that acceptance reading as the reason.

Two corrections to my own work, kept because they are the finding:

* I predicted three tests would flip from the multiply fix alone and that the
  three `alpha_*` would not move. One flipped; all six moved once the binding
  was fixed too. The prediction was wrong in both directions and the two
  defects are one class at two sites.
* The `ExprLiteral` arm first read `extra_kind == "float" || value.contains('.')`.
  Nothing in this compiler ever sets `extra_kind` to "float" -- a condition
  invented rather than read. It is gone. The mutation that found it was itself
  broken first (`false && A || B` disables only the left disjunct), so the arm
  looked dead when the instrument was.

Mutation-checked, 5 of 5 killed: always-ladder, always-reg, everything-is-real,
a-call-is-never-real, a-literal-is-never-real. `verilog_r_si_1.rs` is the
control that the integer path is unchanged; it stays green.
`rustfmt --check` reports 315 complaints on compiler.rs before and 315 after.

Closes #2990
Refs #741, #2987
@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-30 21:20:37 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)=fd84214651ae != 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

PR Dashboard

Generated at: 2026-08-30 21:22:10 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)=fd84214651ae != 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.

ci-gates 422-425: an artifact control is not an emitter repair; a boolean
mutation that respects precedence; a condition invented rather than read; and a
test passing on the one input that survives the bug.

Refs #2990
@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-30 21:23:17 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)=fd84214651ae != 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).

check_now_entry_shape.py requires `# NOW -- <title> (YYYY-MM-DD)` as the first
line plus a `## ` section heading. docs/now/README.md describes only the OTHER
gate's three conditions (presence, freshness, a heading and a bullet), so the
shape this one enforces is not written down beside it.

Refs #2990
@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-30 21:30:28 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)=fd84214651ae != 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).

…ce printed

The skip guard tested `log.contains("not found")`. The runner prints
`No such file or directory (os error 2)`, so the guard never fired and the
assertion ran against an error message -- test-ratchet named this test as newly
failing. A skip path written for one environment and never executed in it.

Both legs are now run before committing: with iverilog on PATH the runtime leg
executes and passes; with it stripped the test prints its reason and passes.

ci-gates 426.

Refs #2990
@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-30 21:34:07 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)=fd84214651ae != 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 9adbb69 into master Aug 30, 2026
37 checks passed
@gHashTag
gHashTag deleted the w42-verilog-break branch August 30, 2026 21:44
gHashTag added a commit that referenced this pull request Aug 30, 2026
…cking gate

Measured with a committed entry in the wrong shape:

  tri hooks now-gate      exit 0    "NOW gate PASSED"
  t27c check-now          exit 0    "build authorized"
  scripts/verify.sh                 "gates:OK"
  check_now_entry_shape   exit 1    "FAIL: 1 of 3 entr(y/ies) do not say
                                     anything checkable"

The last is the REQUIRED `check` context. docs/now/README.md documents the other
gate's three conditions and then says the same three are what the local tools
enforce; the shape condition -- a `# NOW -- <title> (YYYY-MM-DD)` first line and
a `## ` section heading -- is previewed by nothing. The two local tools also name
a different entry than the one the change adds: they answer "is the newest entry
fresh", not "is the added entry well formed".

Found by paying for it: this made `check` red on #2991.

Refs #2987
gHashTag added a commit that referenced this pull request Aug 30, 2026
…RUN (#2993)

* feat(tri): vsim funnel -- how far each spec gets when its Verilog is RUN

The one arm that can catch a defect whose nature is that it COMPILES is the one
that simulates, and its gate has had no targets since specs/scratch was
untracked in #2283 (#2987). Pointing it at the corpus by hand produced four
defects in one sitting: #2988, #2989, #2990 and #2869.

Repairing the gate is half a line and half a decision about 260 baselines for
subjects that no longer exist. The measurement should not wait for it.

Measured at 487003f over 650 specs:
  refused by gen-verilog-for-simulation    69
  iverilog rejected the testbench         410
  simulation exited non-zero                0
  ran and REPORTED FAILURES                10
  ran and produced a verdict              106
  ran, exit 0, and said NOTHING            55
  650 of 650 accounted for.

Three properties worth naming:

*  is its own row. run_icarus_simulate bails only on a line saying
  FAILED, so `checked everything and passed` and `checked nothing` are the
  same exit code. A spec there is not passing; nothing asked it anything.
* One TMPDIR per spec, because run_icarus_simulate keys its scratch file on the
  BASENAME alone and this corpus shares stems.
* It refuses when iverilog or t27c is absent rather than printing a table it did
  not earn, and asks the OS rather than matching an error message (ci-gates 426).

It reports and never gates: which of the 10 are compiler defects and which are
spec defects is not a question a walker may answer.

Refs #2987

* docs: correct the previous commit message, and close the backtick class

The message for `tri vsim funnel` was passed inline to `git commit -m "..."`.
Double quotes do not stop command substitution, so the span naming the `silent`
row was executed and removed:

    * `silent` is its own row.      ->      *  is its own row.

zsh printed `command not found: silent`, which is the only reason it was seen.
The commit is pushed and this repository forbids force-pushing, so the message
stands with the hole and this is the correction. The missing word is `silent` --
the row for a spec that ran, exited 0, and printed no verdict line at all.

ci-gates 418 already says to quote a heredoc delimiter when the body carries a
backtick. That is too narrow: this went through the argument list instead. 427
names the class -- prose containing a backtick never reaches the shell as an
argument; write it to a file or pipe it through a QUOTED heredoc and let git
read it with `-F -`.

Third occurrence in this repository's log, which by its own rule means the cure
was wrong rather than that this is another case.

Refs #2987

* docs(now): record that the local NOW preview does not preview the blocking gate

Measured with a committed entry in the wrong shape:

  tri hooks now-gate      exit 0    "NOW gate PASSED"
  t27c check-now          exit 0    "build authorized"
  scripts/verify.sh                 "gates:OK"
  check_now_entry_shape   exit 1    "FAIL: 1 of 3 entr(y/ies) do not say
                                     anything checkable"

The last is the REQUIRED `check` context. docs/now/README.md documents the other
gate's three conditions and then says the same three are what the local tools
enforce; the shape condition -- a `# NOW -- <title> (YYYY-MM-DD)` first line and
a `## ` section heading -- is previewed by nothing. The two local tools also name
a different entry than the one the change adds: they answer "is the newest entry
fresh", not "is the added entry well formed".

Found by paying for it: this made `check` red on #2991.

Refs #2987

---------

Co-authored-by: Claude <noreply@anthropic.com>
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.

gen-verilog rounds every float multiply to an integer: ewma_step returns 5.0 where all three other backends say 6.5

2 participants