Skip to content

fix(specs): explicit wrapping arithmetic in 4 saturating-add helpers + add to zig gate - #363

Merged
gHashTag merged 1 commit into
mainfrom
fix/wrapping-arith-zig-gate
Aug 9, 2026
Merged

fix(specs): explicit wrapping arithmetic in 4 saturating-add helpers + add to zig gate#363
gHashTag merged 1 commit into
mainfrom
fix/wrapping-arith-zig-gate

Conversation

@gHashTag

@gHashTag gHashTag commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Four execution-orphan specs (from the wave-52/53 audit) used plain +/- inside the classic wrap-detect saturating idiom (let sum = a + b; if (sum < a) return MAX;) and a counter delta (t_end - t_start). C and Verilog wrap unsigned overflow silently — so the overflow check works and both pass — but zig-safe arithmetic panics on the intermediate overflow before the guard runs. That is exactly why these 4 sat in the C+Verilog gates only.

Switching those sites to the wrapping operators +%/-% is a no-op for C and Verilog (they already wrap by width) and makes the intent explicit for Zig:

spec sites
tri_compute_account bal_add_sat, escrow_add_sat, outstanding_after_escrow
tri_compute_pool pool_after_deposit, balance_after_pool_settle
tri_compute_bond balance_after_resolve
twr_timestamp elapsed (wrapping counter delta)

All four now pass zig test (21/21, 13/13, 8/8, 6/6) with icarus and C still green. Committed their gen/zig and added them to the Zig drift diff. gen/c is byte-identical (the wrapping op lowers to plain +/- in C), so the C gates are unaffected.

tri_settle is NOT included: it has a separate blocker — reward_weighted does a u64 -> u32 narrowing cast that gen-zig lowers to a checked @intCast (panics on 2^32) instead of a truncating @truncate. That's a gen-zig codegen fix, tracked for a compiler wave.

gen/zig files are a legitimate regeneration committed via the no-gen-edits escape (LEFTHOOK=0); ascii-only (.rs/.t27/.v) verified manually.

🤖 Generated with Claude Code

…+ add to zig gate

Four specs used plain '+'/'-' inside the classic wrap-detect saturating
idiom (let sum = a + b; if (sum < a) return MAX;) and inside a
counter-delta (t_end - t_start). C and Verilog wrap unsigned overflow
silently, so the overflow check works and both backends pass -- but
zig-safe arithmetic PANICS on the intermediate overflow before the
guard runs, which is exactly why these four sat only in the C+Verilog
gates.

Switch those sites to the wrapping operators '+%'/'-%', which is a
no-op for the C and Verilog backends (they already wrap by width) and
makes the intent explicit for Zig:

  tri_compute_account : bal_add_sat, escrow_add_sat, outstanding_after_escrow
  tri_compute_pool    : pool_after_deposit, balance_after_pool_settle
  tri_compute_bond    : balance_after_resolve
  twr_timestamp       : elapsed (wrapping counter delta)

All four now pass under zig test (21/21, 13/13, 8/8, 6/6) with icarus
and C still green. Committed their gen/zig and added them to the Zig
drift diff. gen/c is byte-identical (the wrapping op lowers to plain
+/- in C), so the C gates are unaffected.

tri_settle is NOT included: it has a separate blocker -- reward_weighted
does a u64->u32 narrowing cast that gen-zig lowers to a checked
@intcast (panics on 2^32) instead of a truncating @truncate. That is a
gen-zig codegen fix, tracked for a compiler wave.

gen/zig files are a legitimate regeneration (no-gen-edits escape,
LEFTHOOK=0); ascii-only (.rs/.t27/.v) verified on the specs manually.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@gHashTag
gHashTag merged commit ca18e0d into main Aug 9, 2026
4 checks passed
@gHashTag
gHashTag deleted the fix/wrapping-arith-zig-gate branch August 9, 2026 01:37
gHashTag added a commit that referenced this pull request Aug 9, 2026
…both (#373)

The zig-test gate compiles and RUNS committed gens -- it is a real
execution gate, not just a drift diff -- but it still iterated a
hand-maintained list while gen/zig became the SSOT for drift in #365.
The list had drifted: six specs had committed, drift-checked gens that
were NEVER EXECUTED here --

  rti_security, tri_compute_account, tri_compute_bond,
  tri_compute_pool, tri_settle, twr_timestamp

precisely the specs closed in the execution-orphan series (#361, #363,
#368). Their gens were verified locally at the time; CI never ran them.

Iterate gen/zig directly, so a newly committed gen auto-joins execution
the same way it auto-joins drift. Verified locally over the FULL
committed set: zig test 107/107, zero failures.

Also applies the #372 coverage-floor pattern to both execution gates
(zig 107, C 75). A loop that silently matched zero files previously
reported green having executed NOTHING; now it fails loudly. C-exec was
already dynamic (#365) but had no floor.

The stale 'gated to the passing set / tracked in t27#1928' header is
corrected: the saturation idiom it referred to is fixed in-spec via
'+%', and the whole committed set passes.

Verified: zig 107/107 executed, C 75/75 executed, both exit 0; a
zero-match loop correctly trips the floor.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: SSD DDD <ssdm4@MacBook-Pro.local>
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