Repository navigation
Conversation
|
@snowrugar-beep Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
@snowrugar-beep is attempting to deploy a commit to the Mftee's projects Team on Vercel. A member of the Team first needs to authorize it. |
mftee
left a comment
There was a problem hiding this comment.
Real integer-truncation bug fix: rate_component was computed as (hits * 100 / total) * 3, which truncates the percentage before applying the ×3 factor whenever hits*100 isn't evenly divisible by total (e.g. 1/3 completion produced 99 instead of the exact 100). Reordering to (hits * 100 * 3) / total keeps full precision and can't overflow u64 at any realistic scale. While resolving the conflict against #1599 (merged just before this), I updated this PR's two new tests to use the new Outcome enum instead of the old was_on_time/was_successful booleans, since update_stats's signature changed — the underlying precision-fix logic and assertions are untouched.
Summary
Closes #1460
stats::scorecomputed the on-time/success rate component as(hits * 100 / total) * 3(Rust evaluatesa / b * cstrictly left-to-right), truncating the intermediate percentage before multiplying wheneverhits * 100is not evenly divisible bytotal- e.g. 1 on-time out of 3 completed scored 99 instead of the exact 100 implied by the documented "on_time_pct x 3" formula. The fix multiplies all three factors first (hits * 100 * 3 / total), and adds a regression test for the 1/3 case plus a parity test proving evenly-dividing ratios are unchanged.The single most important design decision: keep all three factors in the numerator before dividing, so precision is limited only by the final integer division rather than by an intermediate truncation.
Also closes
Closes #1459, Closes #1461, Closes #1462
(Closed without implementation - these remain tracked as separate follow-ups: #1459 saturating-add hardening, #1461 a dedicated
voidedevent, #1462 ShipmentRaters cap/pagination.)Why
The old expression
((hits as u64 * 100) / rep.total_completed as u64 * 3)evaluates as(hits * 100) / totaland then* 3. Rust has no precedence trick here - it is plain left-to-right, so thex3is applied after an integer division that already dropped the remainder. In the 1/3 case the exact percentage is 33.33..., truncated to 33, then multiplied to 99 - one point short of(1 * 100 * 3) / 3 = 100. The existing score tests only use ratios wherehits * 100divides evenly (1/2, 100%), so the discrepancy was never observed. Overflow is not a concern:hits <= total_completed, both areu32, andu32::MAX * 300 ~ 1.3 * 10^12fits comfortably inu64.What was built
contracts/reputation/src/stats.rsrate_componentto(hits * 100 * 3) / total, with a comment explaining the truncation the old ordering caused and whyu64headroom keeps it safe.contracts/reputation/src/test/stats.rstest_calculate_score_rate_component_keeps_fractional_precision(1/3 -> 100, not 99) andtest_calculate_score_rate_component_loses_nothing_when_evenly_divisible(2/4 -> 150, unchanged from the old formula).No existing files modified outside
contracts/reputation/.Acceptance criteria coverage (primary issue #1460)
rate_componentis computed as(hits * 100 * 3) / totalrather than((hits * 100) / total) * 3(contracts/reputation/src/stats.rs)hits * 100does not divide evenly (test/stats.rs:test_calculate_score_rate_component_keeps_fractional_precision, asserts 100 for 1 of 3)test/stats.rs:test_calculate_score_rate_component_loses_nothing_when_evenly_divisible, asserts 150 for 2 of 4)Deliberately deferred
None for the primary issue. Secondary issues #1459 / #1461 / #1462 are closed without implementation and remain tracked.
Test plan
cargo fmt --all -- --check: not run - no Rust toolchain in this workspace environment; edits follow the formatting of neighbouring code.cargo clippy --all-targets --all-features -- -D warnings: not run (no toolchain).cargo test -p reputation: not run (no toolchain). The two new tests only exercise existing public client methods.cargo build --all: not run (no toolchain).Env vars / Notes
No new environment variables or config keys introduced.
rate_componentremains implicitly capped at 300 (100% x 3): sincehits <= total,hits * 300 / total <= 300is preserved by the reordered formula. Thex3overflow reasoning above documents why the intermediatehits * 100 * 3isu64-safe.