From 81aed807cca42ba6fcd7306f00470849f5f7c1a5 Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Sun, 4 Oct 2026 15:12:10 +0000 Subject: [PATCH 1/7] deps: rain-math-float 0.2.5, forge-std 1.17.0 Co-Authored-By: Claude Fable 5.1 --- README.md | 14 +++++++------- foundry.toml | 4 ++-- soldeer.lock | 16 ++++++++-------- src/lib/LibLeakyBucket.sol | 2 +- test/abstract/LeakyBucketAsserts.sol | 4 ++-- test/abstract/LeakyBucketScratch.sol | 2 +- test/concrete/GasBucket.sol | 2 +- test/concrete/LeakyBucketHandler.sol | 4 ++-- test/concrete/LeakyBucketMintCap.sol | 2 +- test/lib/FloatWords.sol | 2 +- test/lib/LibLeakyBucketSlow.sol | 2 +- test/lib/WorkedPolicy.sol | 2 +- test/src/lib/CapacityBound.t.sol | 4 ++-- test/src/lib/FloatHazards.t.sol | 4 ++-- test/src/lib/LeakyBucketEmbedding.t.sol | 4 ++-- test/src/lib/LeakyBucketInvariant.t.sol | 4 ++-- test/src/lib/LibLeakyBucket.t.sol | 6 +++--- test/src/lib/LibLeakyBucketGas.t.sol | 4 ++-- 18 files changed, 41 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index aec52ca..ffc96c4 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,11 @@ unresolved import. Install both: ``` forge soldeer install rain-lib-leakybucket~x.y.z -forge soldeer install rain-math-float~0.2.4 +forge soldeer install rain-math-float~0.2.5 ``` -`0.2.4` there is exact, not a floor. `src/lib/LibLeakyBucket.sol` imports -`rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol` by that literal path, and +`0.2.5` there is exact, not a floor. `src/lib/LibLeakyBucket.sol` imports +`rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol` by that literal path, and soldeer keys the remapping it generates on the installed directory name, so any other revision of `rain-math-float` is remapped under a different prefix and the import does not resolve. @@ -97,7 +97,7 @@ so an untouched mapping entry is already a valid bucket that can mint nothing, and no initializer is needed. ```solidity -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LibLeakyBucket, LeakyBucket} from "rain-lib-leakybucket-x.y.z/src/lib/LibLeakyBucket.sol"; contract Token { @@ -301,7 +301,7 @@ second, with a write on each of those seconds, is still exactly full after half an hour of it. Outside those bounds it holds to the precision of the level and no further. A -`Float` subtraction keeps about 67 digits, and `rain.math.float` at `0.2.4` does +`Float` subtraction keeps about 67 digits, and `rain.math.float` at `0.2.5` does not direct its rounding, so a leak below the last digit the level holds is not taken off as it is. `test/src/lib/FloatHazards.t.sol` pins both outcomes against a level of `1e40`, whose last digit is `1e-27`: a leak of `1e-29` takes a whole @@ -328,7 +328,7 @@ visible. Round down, so the on chain rate is never faster than the policy. ### Arithmetic, and which way it fails Every operation is a `Float` operation from -[`rain.math.float`](https://github.com/rainlanguage/rain.math.float) at `0.2.4`. +[`rain.math.float`](https://github.com/rainlanguage/rain.math.float) at `0.2.5`. Eight distinct operations in the whole file: `add`, `sub`, `mul`, `max`, `lt`, `gt`, `isZero` and the `packLossless` that spells zero. There is no saturating math, no packing, no `unchecked` block, no assembly and no hand rolled overflow @@ -474,7 +474,7 @@ in CI. Not yet audited. The intended scope is `src/`, which is one file, plus the one dependency it imports by path: `LibDecimalFloat` from `rain-math-float` at -`0.2.4`. Every number in a bucket is a `Float` and every operation on one is +`0.2.5`. Every number in a bucket is a `Float` and every operation on one is that library's, so a review of this library's arithmetic is a review of how it calls that one. Nothing in this repo, and nothing in the published `rain-math-float` package, records an audit of it — the Protofire audit of diff --git a/foundry.toml b/foundry.toml index a2aa386..ea27232 100644 --- a/foundry.toml +++ b/foundry.toml @@ -15,11 +15,11 @@ libs = ["dependencies"] fuzz.runs = 4096 [dependencies] -forge-std = "1.16.2" +forge-std = "1.17.0" # Every field of a bucket is a `Float`: the level, the capacity, the leak rate # and the timestamp. Saturation is gone with the fixed point, since a `Float` # has no type boundary a bucket reaches; what remains is the clamp at zero. -"rain-math-float" = "0.2.4" +"rain-math-float" = "0.2.5" [soldeer] recursive_deps = false diff --git a/soldeer.lock b/soldeer.lock index 93f09b4..13cfccf 100644 --- a/soldeer.lock +++ b/soldeer.lock @@ -1,13 +1,13 @@ [[dependencies]] name = "forge-std" -version = "1.16.2" -url = "https://soldeer-revisions.s3.amazonaws.com/forge-std/1_16_2_03-07-2026_07:37:45_forge-std-1.16.zip" -checksum = "405dccc9d60d753f6abc412b4adf0359f4390f65dbadbbb277a12b4946ed8969" -integrity = "5fb4325b60d7d4194bd0481e2f94398cf1d9c6561dd12a66fb2748ef4a68205f" +version = "1.17.0" +url = "https://soldeer-revisions.s3.amazonaws.com/forge-std/1_17_0_01-10-2026_10:59:49_forge-std-1.17.zip" +checksum = "a77ad38d5fbef0ec10d1f4d191698e5fbaa2bffbee5d1aced91a39da5e9b908c" +integrity = "fa706c8a7caf3426c90f75e6aafa3224b0a6c899b490800cf6944e4ec42f9344" [[dependencies]] name = "rain-math-float" -version = "0.2.4" -url = "https://soldeer-revisions.s3.amazonaws.com/rain-math-float/0_2_4_27-09-2026_15:02:57_rain.math.zip" -checksum = "a13f6e73e32324a38a2da2826484c2a03dd1ed1514851c557d90ec8f3323b940" -integrity = "70b5b63f234f24b7719bf6a296caafb9120ce185d7a3dced231a660aca7adf83" +version = "0.2.5" +url = "https://soldeer-revisions.s3.amazonaws.com/rain-math-float/0_2_5_02-10-2026_10:34:50_rain.math.zip" +checksum = "403c9a47d91114bbcaffbfe4d9c4240f7e760f86b896daa6d75d1ca891cc72b8" +integrity = "b14524ac29868af6dbaabd1086f53e142b8f1170d994972eb948fa646f817768" diff --git a/src/lib/LibLeakyBucket.sol b/src/lib/LibLeakyBucket.sol index a460123..2580266 100644 --- a/src/lib/LibLeakyBucket.sol +++ b/src/lib/LibLeakyBucket.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; /// A fill of `amount` does not fit: `level + amount > capacity`. error LeakyBucketCapacityExceeded(Float capacity, Float level, Float amount); diff --git a/test/abstract/LeakyBucketAsserts.sol b/test/abstract/LeakyBucketAsserts.sol index c241ec1..9964c67 100644 --- a/test/abstract/LeakyBucketAsserts.sol +++ b/test/abstract/LeakyBucketAsserts.sol @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Test} from "forge-std-1.16.2/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Test} from "forge-std-1.17.0/src/Test.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LeakyBucketCapacityExceeded} from "../../src/lib/LibLeakyBucket.sol"; import {LeakyBucketScratch} from "./LeakyBucketScratch.sol"; diff --git a/test/abstract/LeakyBucketScratch.sol b/test/abstract/LeakyBucketScratch.sol index 4a821d3..a2eca36 100644 --- a/test/abstract/LeakyBucketScratch.sol +++ b/test/abstract/LeakyBucketScratch.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LibLeakyBucket, LeakyBucket} from "../../src/lib/LibLeakyBucket.sol"; /// @title LeakyBucketScratch diff --git a/test/concrete/GasBucket.sol b/test/concrete/GasBucket.sol index cea635b..d4efa5f 100644 --- a/test/concrete/GasBucket.sol +++ b/test/concrete/GasBucket.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LibLeakyBucket, LeakyBucket} from "../../src/lib/LibLeakyBucket.sol"; /// @title GasBucket diff --git a/test/concrete/LeakyBucketHandler.sol b/test/concrete/LeakyBucketHandler.sol index c55e805..7f346c7 100644 --- a/test/concrete/LeakyBucketHandler.sol +++ b/test/concrete/LeakyBucketHandler.sol @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Test} from "forge-std-1.16.2/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Test} from "forge-std-1.17.0/src/Test.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LeakyBucketMintCap} from "./LeakyBucketMintCap.sol"; import {LeakyBucketCapacityExceeded} from "../../src/lib/LibLeakyBucket.sol"; import {LeakyBucketAsserts} from "../abstract/LeakyBucketAsserts.sol"; diff --git a/test/concrete/LeakyBucketMintCap.sol b/test/concrete/LeakyBucketMintCap.sol index 1de80b2..8ad6517 100644 --- a/test/concrete/LeakyBucketMintCap.sol +++ b/test/concrete/LeakyBucketMintCap.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LibLeakyBucket, LeakyBucket} from "../../src/lib/LibLeakyBucket.sol"; /// @title LeakyBucketMintCap diff --git a/test/lib/FloatWords.sol b/test/lib/FloatWords.sol index 52bb8da..f5a8620 100644 --- a/test/lib/FloatWords.sol +++ b/test/lib/FloatWords.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; /// A whole number as a `Float` at exponent zero. /// diff --git a/test/lib/LibLeakyBucketSlow.sol b/test/lib/LibLeakyBucketSlow.sol index d1f0798..6c8ceeb 100644 --- a/test/lib/LibLeakyBucketSlow.sol +++ b/test/lib/LibLeakyBucketSlow.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; /// @title LibLeakyBucketSlow /// @notice The leak one step at a time, as an oracle for the closed form. diff --git a/test/lib/WorkedPolicy.sol b/test/lib/WorkedPolicy.sol index 51c401b..574374f 100644 --- a/test/lib/WorkedPolicy.sol +++ b/test/lib/WorkedPolicy.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {float} from "./FloatWords.sol"; // The worked policy: a 3600 unit burst draining at one unit per second. diff --git a/test/src/lib/CapacityBound.t.sol b/test/src/lib/CapacityBound.t.sol index df32192..ff8c824 100644 --- a/test/src/lib/CapacityBound.t.sol +++ b/test/src/lib/CapacityBound.t.sol @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Test} from "forge-std-1.16.2/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Test} from "forge-std-1.17.0/src/Test.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LeakyBucketCapacityExceeded} from "../../../src/lib/LibLeakyBucket.sol"; import {workedCapacity, workedLeakRate, workedDrain, capacityOver} from "../../lib/WorkedPolicy.sol"; import {LeakyBucketAsserts} from "../../abstract/LeakyBucketAsserts.sol"; diff --git a/test/src/lib/FloatHazards.t.sol b/test/src/lib/FloatHazards.t.sol index 6507e29..5c4175d 100644 --- a/test/src/lib/FloatHazards.t.sol +++ b/test/src/lib/FloatHazards.t.sol @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Test} from "forge-std-1.16.2/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Test} from "forge-std-1.17.0/src/Test.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import { LibLeakyBucket, LeakyBucket, diff --git a/test/src/lib/LeakyBucketEmbedding.t.sol b/test/src/lib/LeakyBucketEmbedding.t.sol index 0e4ab6d..784f113 100644 --- a/test/src/lib/LeakyBucketEmbedding.t.sol +++ b/test/src/lib/LeakyBucketEmbedding.t.sol @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Test} from "forge-std-1.16.2/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Test} from "forge-std-1.17.0/src/Test.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LeakyBucketMintCap} from "../../concrete/LeakyBucketMintCap.sol"; import { LeakyBucketCapacityExceeded, diff --git a/test/src/lib/LeakyBucketInvariant.t.sol b/test/src/lib/LeakyBucketInvariant.t.sol index f9abddb..6a521d6 100644 --- a/test/src/lib/LeakyBucketInvariant.t.sol +++ b/test/src/lib/LeakyBucketInvariant.t.sol @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Test} from "forge-std-1.16.2/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Test} from "forge-std-1.17.0/src/Test.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {LeakyBucketMintCap} from "../../concrete/LeakyBucketMintCap.sol"; import {LeakyBucketHandler} from "../../concrete/LeakyBucketHandler.sol"; diff --git a/test/src/lib/LibLeakyBucket.t.sol b/test/src/lib/LibLeakyBucket.t.sol index 248dbb5..febf0a9 100644 --- a/test/src/lib/LibLeakyBucket.t.sol +++ b/test/src/lib/LibLeakyBucket.t.sol @@ -2,9 +2,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Test} from "forge-std-1.16.2/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; -import {ExponentOverflow} from "rain-math-float-0.2.4/src/error/ErrDecimalFloat.sol"; +import {Test} from "forge-std-1.17.0/src/Test.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {ExponentOverflow} from "rain-math-float-0.2.5/src/error/ErrDecimalFloat.sol"; import { LeakyBucket, LeakyBucketCapacityExceeded, diff --git a/test/src/lib/LibLeakyBucketGas.t.sol b/test/src/lib/LibLeakyBucketGas.t.sol index a903860..b06fd92 100644 --- a/test/src/lib/LibLeakyBucketGas.t.sol +++ b/test/src/lib/LibLeakyBucketGas.t.sol @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Test, console2} from "forge-std-1.16.2/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.4/src/lib/LibDecimalFloat.sol"; +import {Test, console2} from "forge-std-1.17.0/src/Test.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; import {GasBucket} from "../../concrete/GasBucket.sol"; import {LeakyBucketCapacityExceeded} from "../../../src/lib/LibLeakyBucket.sol"; import {workedCapacity, workedLeakRate, workedDrain} from "../../lib/WorkedPolicy.sol"; From aa039e58d18a0c8ea29c69d76b0c995064fbd63f Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Sun, 4 Oct 2026 15:23:16 +0000 Subject: [PATCH 2/7] audit: record the scan against rain-math-float 0.2.5 Co-Authored-By: Claude Fable 5.1 --- audit/mutation-test-scans.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/audit/mutation-test-scans.json b/audit/mutation-test-scans.json index 11ff963..e02d506 100644 --- a/audit/mutation-test-scans.json +++ b/audit/mutation-test-scans.json @@ -451,5 +451,28 @@ "filed": [], "notes": "One record for the whole pull request. At the named commit: green 82 baseline, mutation-probe over mutants.toml M01 to M33, 33/33 killed, 0 survived, 0 no-run, 0 harness errors. The before figures are the previous entry's: 22 mutants, all killed by the 63 tests on main. The other 11 mutants target settle, setPolicy and the shared leak, which do not exist on main, so they have no before verdict; some of the 22 were retargeted at the new spelling of the line they mutate. No adversarial pass was run." } + }, + { + "timestamp": "2026-10-04T15:23:16Z", + "commit": "81aed807cca42ba6fcd7306f00470849f5f7c1a5", + "testsAfterCommit": "81aed807cca42ba6fcd7306f00470849f5f7c1a5", + "publishedTag": "sol-v0.4.4", + "commitsAheadOfTag": 1, + "scope": "src/lib/LibLeakyBucket.sol against rain-math-float 0.2.5 and forge-std 1.17.0; the only source change is the float import path.", + "tool": "adversarial-mutation-test", + "skillVersion": "0.35.0", + "summary": { + "behaviours": 33, + "mutantsKilledByPreExistingSuite": 33, + "mutantsSurvivedPreExistingSuite": 0, + "mutantsKilledAfter": 33, + "candidates": 0, + "confirmed": 0, + "testsBefore": 82, + "testsAfter": 82, + "coveragePRs": [], + "filed": [], + "notes": "mutation-probe over mutants.toml M01 to M33 at the named commit: green 82 baseline, 33/33 killed, 0 survived, 0 no-run, 0 harness errors. No test or mutant changed; the suite and the mutants are the previous entry's, run against the bumped dependencies. No adversarial pass was run." + } } ] From e772c127dded6286455862911cecd7da5c8e105a Mon Sep 17 00:00:00 2001 From: David Meister Date: Sun, 11 Oct 2026 16:06:58 +0000 Subject: [PATCH 3/7] deps: rain-math-float 0.2.22 Moves the float import path in src/ and test/, the lock, and the README's install line and pin sentences from 0.2.5 to 0.2.22, the revision st0x.deploy main builds against. Co-Authored-By: Claude Opus 5.5 (1M context) --- README.md | 33 +++++++++++++------------ foundry.toml | 2 +- soldeer.lock | 8 +++--- src/lib/LibLeakyBucket.sol | 2 +- test/abstract/LeakyBucketAsserts.sol | 2 +- test/abstract/LeakyBucketScratch.sol | 2 +- test/concrete/GasBucket.sol | 2 +- test/concrete/LeakyBucketHandler.sol | 2 +- test/concrete/LeakyBucketMintCap.sol | 2 +- test/lib/FloatWords.sol | 2 +- test/lib/LibLeakyBucketSlow.sol | 2 +- test/lib/WorkedPolicy.sol | 2 +- test/src/lib/CapacityBound.t.sol | 2 +- test/src/lib/FloatHazards.t.sol | 2 +- test/src/lib/LeakyBucketEmbedding.t.sol | 2 +- test/src/lib/LeakyBucketInvariant.t.sol | 2 +- test/src/lib/LibLeakyBucket.t.sol | 4 +-- test/src/lib/LibLeakyBucketGas.t.sol | 2 +- 18 files changed, 38 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index ffc96c4..3a43b45 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,11 @@ unresolved import. Install both: ``` forge soldeer install rain-lib-leakybucket~x.y.z -forge soldeer install rain-math-float~0.2.5 +forge soldeer install rain-math-float~0.2.22 ``` -`0.2.5` there is exact, not a floor. `src/lib/LibLeakyBucket.sol` imports -`rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol` by that literal path, and +`0.2.22` there is exact, not a floor. `src/lib/LibLeakyBucket.sol` imports +`rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol` by that literal path, and soldeer keys the remapping it generates on the installed directory name, so any other revision of `rain-math-float` is remapped under a different prefix and the import does not resolve. @@ -97,7 +97,7 @@ so an untouched mapping entry is already a valid bucket that can mint nothing, and no initializer is needed. ```solidity -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LibLeakyBucket, LeakyBucket} from "rain-lib-leakybucket-x.y.z/src/lib/LibLeakyBucket.sol"; contract Token { @@ -301,12 +301,12 @@ second, with a write on each of those seconds, is still exactly full after half an hour of it. Outside those bounds it holds to the precision of the level and no further. A -`Float` subtraction keeps about 67 digits, and `rain.math.float` at `0.2.5` does -not direct its rounding, so a leak below the last digit the level holds is not -taken off as it is. `test/src/lib/FloatHazards.t.sol` pins both outcomes against -a level of `1e40`, whose last digit is `1e-27`: a leak of `1e-29` takes a whole -`1e-27` off, and a leak of `1e-37` takes nothing. A read does that once. A -checkpoint does it once per checkpoint, because the stored timestamp advances +`Float` subtraction keeps about 67 digits, and `rain.math.float` at `0.2.22` +does not direct its rounding, so a leak below the last digit the level holds is +not taken off as it is. `test/src/lib/FloatHazards.t.sol` pins both outcomes +against a level of `1e40`, whose last digit is `1e-27`: a leak of `1e-29` takes +a whole `1e-27` off, and a leak of `1e-37` takes nothing. A read does that once. +A checkpoint does it once per checkpoint, because the stored timestamp advances over the time whose leak was rounded. Ten settles a second apart at `1e-29` per second leak `1e-26` where the unsettled bucket reads `1e-27` down, which is the permissive direction: a unit in the level's last digit of headroom per @@ -328,11 +328,12 @@ visible. Round down, so the on chain rate is never faster than the policy. ### Arithmetic, and which way it fails Every operation is a `Float` operation from -[`rain.math.float`](https://github.com/rainlanguage/rain.math.float) at `0.2.5`. -Eight distinct operations in the whole file: `add`, `sub`, `mul`, `max`, `lt`, -`gt`, `isZero` and the `packLossless` that spells zero. There is no saturating -math, no packing, no `unchecked` block, no assembly and no hand rolled overflow -guard anywhere in `src/`, because a bucket has no width to overflow. +[`rain.math.float`](https://github.com/rainlanguage/rain.math.float) at +`0.2.22`. Eight distinct operations in the whole file: `add`, `sub`, `mul`, +`max`, `lt`, `gt`, `isZero` and the `packLossless` that spells zero. There is no +saturating math, no packing, no `unchecked` block, no assembly and no hand +rolled overflow guard anywhere in `src/`, because a bucket has no width to +overflow. What is left of the old saturation is the clamps at zero, and the direction of each is a security argument rather than a style choice: @@ -474,7 +475,7 @@ in CI. Not yet audited. The intended scope is `src/`, which is one file, plus the one dependency it imports by path: `LibDecimalFloat` from `rain-math-float` at -`0.2.5`. Every number in a bucket is a `Float` and every operation on one is +`0.2.22`. Every number in a bucket is a `Float` and every operation on one is that library's, so a review of this library's arithmetic is a review of how it calls that one. Nothing in this repo, and nothing in the published `rain-math-float` package, records an audit of it — the Protofire audit of diff --git a/foundry.toml b/foundry.toml index ea27232..bc3aa3e 100644 --- a/foundry.toml +++ b/foundry.toml @@ -19,7 +19,7 @@ forge-std = "1.17.0" # Every field of a bucket is a `Float`: the level, the capacity, the leak rate # and the timestamp. Saturation is gone with the fixed point, since a `Float` # has no type boundary a bucket reaches; what remains is the clamp at zero. -"rain-math-float" = "0.2.5" +"rain-math-float" = "0.2.22" [soldeer] recursive_deps = false diff --git a/soldeer.lock b/soldeer.lock index 13cfccf..3da8261 100644 --- a/soldeer.lock +++ b/soldeer.lock @@ -7,7 +7,7 @@ integrity = "fa706c8a7caf3426c90f75e6aafa3224b0a6c899b490800cf6944e4ec42f9344" [[dependencies]] name = "rain-math-float" -version = "0.2.5" -url = "https://soldeer-revisions.s3.amazonaws.com/rain-math-float/0_2_5_02-10-2026_10:34:50_rain.math.zip" -checksum = "403c9a47d91114bbcaffbfe4d9c4240f7e760f86b896daa6d75d1ca891cc72b8" -integrity = "b14524ac29868af6dbaabd1086f53e142b8f1170d994972eb948fa646f817768" +version = "0.2.22" +url = "https://soldeer-revisions.s3.amazonaws.com/rain-math-float/0_2_22_07-10-2026_16:03:59_rain.math.zip" +checksum = "d582d8ad93587f3a1192f369ac9302df1991120b39e591a64bdd6a9b5dd47497" +integrity = "890abd3dd075a428420b576c08ca4d3cc458e8c3d99579270a312bf8e9c36480" diff --git a/src/lib/LibLeakyBucket.sol b/src/lib/LibLeakyBucket.sol index 2580266..0e95240 100644 --- a/src/lib/LibLeakyBucket.sol +++ b/src/lib/LibLeakyBucket.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; /// A fill of `amount` does not fit: `level + amount > capacity`. error LeakyBucketCapacityExceeded(Float capacity, Float level, Float amount); diff --git a/test/abstract/LeakyBucketAsserts.sol b/test/abstract/LeakyBucketAsserts.sol index 9964c67..50db99a 100644 --- a/test/abstract/LeakyBucketAsserts.sol +++ b/test/abstract/LeakyBucketAsserts.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.25; import {Test} from "forge-std-1.17.0/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LeakyBucketCapacityExceeded} from "../../src/lib/LibLeakyBucket.sol"; import {LeakyBucketScratch} from "./LeakyBucketScratch.sol"; diff --git a/test/abstract/LeakyBucketScratch.sol b/test/abstract/LeakyBucketScratch.sol index a2eca36..ba14255 100644 --- a/test/abstract/LeakyBucketScratch.sol +++ b/test/abstract/LeakyBucketScratch.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LibLeakyBucket, LeakyBucket} from "../../src/lib/LibLeakyBucket.sol"; /// @title LeakyBucketScratch diff --git a/test/concrete/GasBucket.sol b/test/concrete/GasBucket.sol index d4efa5f..64affb9 100644 --- a/test/concrete/GasBucket.sol +++ b/test/concrete/GasBucket.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LibLeakyBucket, LeakyBucket} from "../../src/lib/LibLeakyBucket.sol"; /// @title GasBucket diff --git a/test/concrete/LeakyBucketHandler.sol b/test/concrete/LeakyBucketHandler.sol index 7f346c7..4ee13d8 100644 --- a/test/concrete/LeakyBucketHandler.sol +++ b/test/concrete/LeakyBucketHandler.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.17.0/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LeakyBucketMintCap} from "./LeakyBucketMintCap.sol"; import {LeakyBucketCapacityExceeded} from "../../src/lib/LibLeakyBucket.sol"; import {LeakyBucketAsserts} from "../abstract/LeakyBucketAsserts.sol"; diff --git a/test/concrete/LeakyBucketMintCap.sol b/test/concrete/LeakyBucketMintCap.sol index 8ad6517..b8c0b44 100644 --- a/test/concrete/LeakyBucketMintCap.sol +++ b/test/concrete/LeakyBucketMintCap.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity =0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LibLeakyBucket, LeakyBucket} from "../../src/lib/LibLeakyBucket.sol"; /// @title LeakyBucketMintCap diff --git a/test/lib/FloatWords.sol b/test/lib/FloatWords.sol index f5a8620..f8e7f62 100644 --- a/test/lib/FloatWords.sol +++ b/test/lib/FloatWords.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; /// A whole number as a `Float` at exponent zero. /// diff --git a/test/lib/LibLeakyBucketSlow.sol b/test/lib/LibLeakyBucketSlow.sol index 6c8ceeb..9135659 100644 --- a/test/lib/LibLeakyBucketSlow.sol +++ b/test/lib/LibLeakyBucketSlow.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; /// @title LibLeakyBucketSlow /// @notice The leak one step at a time, as an oracle for the closed form. diff --git a/test/lib/WorkedPolicy.sol b/test/lib/WorkedPolicy.sol index 574374f..3836b1d 100644 --- a/test/lib/WorkedPolicy.sol +++ b/test/lib/WorkedPolicy.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {float} from "./FloatWords.sol"; // The worked policy: a 3600 unit burst draining at one unit per second. diff --git a/test/src/lib/CapacityBound.t.sol b/test/src/lib/CapacityBound.t.sol index ff8c824..ab1544f 100644 --- a/test/src/lib/CapacityBound.t.sol +++ b/test/src/lib/CapacityBound.t.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.17.0/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LeakyBucketCapacityExceeded} from "../../../src/lib/LibLeakyBucket.sol"; import {workedCapacity, workedLeakRate, workedDrain, capacityOver} from "../../lib/WorkedPolicy.sol"; import {LeakyBucketAsserts} from "../../abstract/LeakyBucketAsserts.sol"; diff --git a/test/src/lib/FloatHazards.t.sol b/test/src/lib/FloatHazards.t.sol index 5c4175d..7422966 100644 --- a/test/src/lib/FloatHazards.t.sol +++ b/test/src/lib/FloatHazards.t.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.17.0/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import { LibLeakyBucket, LeakyBucket, diff --git a/test/src/lib/LeakyBucketEmbedding.t.sol b/test/src/lib/LeakyBucketEmbedding.t.sol index 784f113..7c66be8 100644 --- a/test/src/lib/LeakyBucketEmbedding.t.sol +++ b/test/src/lib/LeakyBucketEmbedding.t.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.17.0/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LeakyBucketMintCap} from "../../concrete/LeakyBucketMintCap.sol"; import { LeakyBucketCapacityExceeded, diff --git a/test/src/lib/LeakyBucketInvariant.t.sol b/test/src/lib/LeakyBucketInvariant.t.sol index 6a521d6..34d3df5 100644 --- a/test/src/lib/LeakyBucketInvariant.t.sol +++ b/test/src/lib/LeakyBucketInvariant.t.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.17.0/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {LeakyBucketMintCap} from "../../concrete/LeakyBucketMintCap.sol"; import {LeakyBucketHandler} from "../../concrete/LeakyBucketHandler.sol"; diff --git a/test/src/lib/LibLeakyBucket.t.sol b/test/src/lib/LibLeakyBucket.t.sol index febf0a9..4cfe99f 100644 --- a/test/src/lib/LibLeakyBucket.t.sol +++ b/test/src/lib/LibLeakyBucket.t.sol @@ -3,8 +3,8 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.17.0/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; -import {ExponentOverflow} from "rain-math-float-0.2.5/src/error/ErrDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; +import {ExponentOverflow} from "rain-math-float-0.2.22/src/error/ErrDecimalFloat.sol"; import { LeakyBucket, LeakyBucketCapacityExceeded, diff --git a/test/src/lib/LibLeakyBucketGas.t.sol b/test/src/lib/LibLeakyBucketGas.t.sol index b06fd92..96e592c 100644 --- a/test/src/lib/LibLeakyBucketGas.t.sol +++ b/test/src/lib/LibLeakyBucketGas.t.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.25; import {Test, console2} from "forge-std-1.17.0/src/Test.sol"; -import {Float, LibDecimalFloat} from "rain-math-float-0.2.5/src/lib/LibDecimalFloat.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.2.22/src/lib/LibDecimalFloat.sol"; import {GasBucket} from "../../concrete/GasBucket.sol"; import {LeakyBucketCapacityExceeded} from "../../../src/lib/LibLeakyBucket.sol"; import {workedCapacity, workedLeakRate, workedDrain} from "../../lib/WorkedPolicy.sol"; From ddaca22a8178e3db95b90df511d76212cac7ea84 Mon Sep 17 00:00:00 2001 From: David Meister Date: Sun, 11 Oct 2026 16:59:08 +0000 Subject: [PATCH 4/7] audit: record the scan against rain-math-float 0.2.22 mutation-probe over mutants.toml M01 to M33 at e772c12: green 82 baseline, 33/33 killed. M25 was re-run alone after the full pass scored it no-run. Co-Authored-By: Claude Opus 5.5 (1M context) --- audit/mutation-test-scans.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/audit/mutation-test-scans.json b/audit/mutation-test-scans.json index e02d506..5e7212e 100644 --- a/audit/mutation-test-scans.json +++ b/audit/mutation-test-scans.json @@ -474,5 +474,28 @@ "filed": [], "notes": "mutation-probe over mutants.toml M01 to M33 at the named commit: green 82 baseline, 33/33 killed, 0 survived, 0 no-run, 0 harness errors. No test or mutant changed; the suite and the mutants are the previous entry's, run against the bumped dependencies. No adversarial pass was run." } + }, + { + "timestamp": "2026-10-11T16:58:44Z", + "commit": "e772c127dded6286455862911cecd7da5c8e105a", + "testsAfterCommit": "e772c127dded6286455862911cecd7da5c8e105a", + "publishedTag": "sol-v0.4.4", + "commitsAheadOfTag": 3, + "scope": "src/lib/LibLeakyBucket.sol against rain-math-float 0.2.22 and forge-std 1.17.0; the only source change is the float import path.", + "tool": "adversarial-mutation-test", + "skillVersion": "0.35.0", + "summary": { + "behaviours": 33, + "mutantsKilledByPreExistingSuite": 33, + "mutantsSurvivedPreExistingSuite": 0, + "mutantsKilledAfter": 33, + "candidates": 0, + "confirmed": 0, + "testsBefore": 82, + "testsAfter": 82, + "coveragePRs": [], + "filed": [], + "notes": "mutation-probe over mutants.toml M01 to M33 at the named commit: green 82 baseline, 33/33 killed, 0 survived, 0 harness errors. The full pass scored 32 killed and M25 no-run (its suite output carried no tally line); M25 re-run alone with --only M25 on a green 82 baseline was killed. M33's kill carries no test names because its failures' counterexamples contain brackets the fail-pattern stops at; the tally shows 79 passed, 3 failed. No test or mutant changed; the suite and the mutants are the previous entry's, run against the bumped dependencies. No adversarial pass was run." + } } ] From db24b0337fc0a8d51428b4d872e69979465e6e7a Mon Sep 17 00:00:00 2001 From: David Meister Date: Sun, 11 Oct 2026 17:04:30 +0000 Subject: [PATCH 5/7] test: pin a leak landing exactly on the exponent floor 0.1 at 30e-2147483648 a second is 30e-2147483649, packed by shedding its trailing zero to 3e-2147483648; a level of 5e-2147483648 reads 2e-2147483648. Co-Authored-By: Claude Opus 5.5 (1M context) --- test/src/lib/FloatHazards.t.sol | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/src/lib/FloatHazards.t.sol b/test/src/lib/FloatHazards.t.sol index 7422966..a2a697e 100644 --- a/test/src/lib/FloatHazards.t.sol +++ b/test/src/lib/FloatHazards.t.sol @@ -89,6 +89,26 @@ contract FloatHazardsTest is Test { assertTrue(LibLeakyBucket.headroomAt(bucket, f(0, 0)).isZero()); } + /// A leak whose exact value sits on the exponent floor is charged in full. + /// + /// 0.1 seconds at 30e-2147483648 a second is a product of 30e-2147483649, + /// one step under the floor; its trailing zero is shed to land it exactly + /// at 3e-2147483648. The level of 5e-2147483648 leaks to exactly + /// 2e-2147483648. A leak that reverted, or underflowed to zero and left + /// the level at 5e-2147483648, or was charged as anything but 3, reads + /// differently. + function testALeakExactlyAtTheExponentFloorIsChargedInFull() external pure { + LeakyBucket memory bucket = LeakyBucket({ + level: f(5, type(int32).min), + timestamp: f(0, 0), + capacity: f(1, 0), + leakRate: f(30, type(int32).min) + }); + + Float levelNow = LibLeakyBucket.levelAt(bucket, f(1, -1)); + assertTrue(levelNow.eq(f(2, type(int32).min)), "level after a leak at the floor"); + } + /// `bucket` settled once a second for `count` seconds, each settle stored. function settledEachSecond(LeakyBucket memory bucket, int256 count) internal pure returns (LeakyBucket memory) { for (int256 i = 1; i <= count; i++) { From 0620121b5e62b8d04987c40168e49600d98799f7 Mon Sep 17 00:00:00 2001 From: David Meister Date: Sun, 11 Oct 2026 17:05:04 +0000 Subject: [PATCH 6/7] test: forge fmt the exponent floor test Co-Authored-By: Claude Opus 5.5 (1M context) --- test/src/lib/FloatHazards.t.sol | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/src/lib/FloatHazards.t.sol b/test/src/lib/FloatHazards.t.sol index a2a697e..e50e36b 100644 --- a/test/src/lib/FloatHazards.t.sol +++ b/test/src/lib/FloatHazards.t.sol @@ -99,10 +99,7 @@ contract FloatHazardsTest is Test { /// differently. function testALeakExactlyAtTheExponentFloorIsChargedInFull() external pure { LeakyBucket memory bucket = LeakyBucket({ - level: f(5, type(int32).min), - timestamp: f(0, 0), - capacity: f(1, 0), - leakRate: f(30, type(int32).min) + level: f(5, type(int32).min), timestamp: f(0, 0), capacity: f(1, 0), leakRate: f(30, type(int32).min) }); Float levelNow = LibLeakyBucket.levelAt(bucket, f(1, -1)); From 1ffbe528148c555a1bda74681fbd72f7182052b0 Mon Sep 17 00:00:00 2001 From: David Meister Date: Sun, 11 Oct 2026 17:30:32 +0000 Subject: [PATCH 7/7] audit: record the scan with the exponent floor test mutation-probe over mutants.toml M01 to M33 at 0620121: green 83 baseline, 33/33 killed. M27, M28 and M33 killers named from hand re-runs. Co-Authored-By: Claude Opus 5.5 (1M context) --- audit/mutation-test-scans.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/audit/mutation-test-scans.json b/audit/mutation-test-scans.json index 5e7212e..0778d74 100644 --- a/audit/mutation-test-scans.json +++ b/audit/mutation-test-scans.json @@ -497,5 +497,28 @@ "filed": [], "notes": "mutation-probe over mutants.toml M01 to M33 at the named commit: green 82 baseline, 33/33 killed, 0 survived, 0 harness errors. The full pass scored 32 killed and M25 no-run (its suite output carried no tally line); M25 re-run alone with --only M25 on a green 82 baseline was killed. M33's kill carries no test names because its failures' counterexamples contain brackets the fail-pattern stops at; the tally shows 79 passed, 3 failed. No test or mutant changed; the suite and the mutants are the previous entry's, run against the bumped dependencies. No adversarial pass was run." } + }, + { + "timestamp": "2026-10-11T17:29:47Z", + "commit": "0620121b5e62b8d04987c40168e49600d98799f7", + "testsAfterCommit": "0620121b5e62b8d04987c40168e49600d98799f7", + "publishedTag": "sol-v0.4.4", + "commitsAheadOfTag": 6, + "scope": "src/lib/LibLeakyBucket.sol against rain-math-float 0.2.22 and forge-std 1.17.0; the suite gains testALeakExactlyAtTheExponentFloorIsChargedInFull, a leak whose product lands exactly on the int32.min exponent floor.", + "tool": "adversarial-mutation-test", + "skillVersion": "0.35.0", + "summary": { + "behaviours": 33, + "mutantsKilledByPreExistingSuite": 33, + "mutantsSurvivedPreExistingSuite": 0, + "mutantsKilledAfter": 33, + "candidates": 0, + "confirmed": 0, + "testsBefore": 82, + "testsAfter": 83, + "coveragePRs": [], + "filed": [], + "notes": "mutation-probe over mutants.toml M01 to M33 at the named commit: green 83 baseline, 33/33 killed, 0 survived, 0 no-run, 0 harness errors. The new test is among the killers of M04 and M06. M27, M28 and M33 carry no test names because their failures' counterexamples contain brackets the fail-pattern stops at; each was re-run by hand under .mutation-test/check.sh with its compile proven: M27 80 passed 3 failed (testEntryPointsAnswerOnExactlyTheFillableDomain, testEntryPointsRejectANegativeCapacity, testEntryPointsRejectANegativeLeakRate), M28 78 passed 5 failed (testEntryPointsRejectANegativeCapacity, testEntryPointsRejectANegativeLeakRate, testSetCapacityRefusesANegativeCapacity, testSetPolicyRefusesANegativeCapacity, testSetPolicyRefusesANegativeLeakRate), M33 80 passed 3 failed (testEntryPointsRejectANegativeLevel, testEntryPointsRejectANegativeStoredTimestamp, testEntryPointsRejectANegativeTimestamp). No mutant changed. No adversarial pass was run." + } } ]