test(numtower): property tests run at the 256-case budget (improvise-59nw.1)

Answers Copilot on PR #337 (context/design-principles.md section 7). Every fault in the review's table still fails by name at 256 cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Claude (numtower)
2026-10-09 00:14:57 -07:00
committed by Edward Langley
parent 34ab0fc3d3
commit f11d27377d
2 changed files with 20 additions and 11 deletions
+15 -6
View File
@@ -105,11 +105,18 @@ to discriminate.
### rust_decimal_to_f64_agrees_on_fifteen_digit_mantissas_so_a_narrow_generator_is_vacuous
This test **passes the rival** on purpose. With mantissas of at most 15 digits, 4,096
cases, `rust_decimal`'s `to_f64` agrees with the text every time, as ADR 005 says (200,000
of 200,000). So a test whose generator stays in that range proves nothing about the
conversion. This test is why the generator above spans 96 bits, and it is what fails, and
should be re-read, if `rust_decimal` ever fixes its conversion.
This test **passes the rival** on purpose. With mantissas of at most 15 digits,
`rust_decimal`'s `to_f64` agrees with the text every time, at this test's 256 cases as
in ADR 005's 200,000 of 200,000. So a test whose generator stays in that range proves
nothing about the conversion, and this test is why the generator above spans 96 bits. It
ran at 4,096 cases until Copilot pointed out, on PR #337, that the repository's budget is
256 (`context/design-principles.md` §7). The 200,000 is the ADR's measurement, and this
test only pins its direction.
If `rust_decimal` ever fixes its conversion, this test still passes. What fails then is
`the_f64_conversion_agrees_with_parsing_the_decimal_text_catches_rust_decimal_to_f64`,
whose rival would agree. That is the signal to re-read both. An earlier version of this
entry named this test instead, which was wrong.
### a_fractions_conversion_lies_inside_the_round_to_nearest_even_interval
@@ -205,7 +212,9 @@ faults passed the whole suite:
- F14: the past-K read dropped the decimal partition;
- F15: the past-K read dropped every inexact term.
The test now has the reviewer's oracle and 512 cases. Half the lists come from the
The test now has the reviewer's oracle, at the repository's 256-case budget. 34ab0fc3 ran
it at 512, and Copilot pointed out the budget. At 256, every fault in the table below
still failed by name, and F7, F8, F12, F14 and F15 failed in four of four passes. Half the lists come from the
fourteen-denominator pool, up to 40 terms long, so groups receive several terms and K is
passed often. **It also counts how many cases reach each branch and fails if any branch
is reached fewer than 20 times**, so a generator change cannot silently starve one.
+5 -5
View File
@@ -93,7 +93,7 @@ fn an_exact_result_is_never_a_rounded_one_catches_a_silently_rounding_add() {
fn check_contagion(add: BinOp, deterministic: bool) -> Result<(), String> {
let seed = Just((dec("2"), Num::inexact(3.0)));
let cases = prop_oneof![1 => seed, 8 => (any_num(), any_num())];
run(cases, 512, deterministic, |(a, b)| {
run(cases, 256, deterministic, |(a, b)| {
let results = [
("+", add(&a, &b)),
("-", Some(&a - &b)),
@@ -310,7 +310,7 @@ fn the_f64_conversion_agrees_with_parsing_the_decimal_text_catches_rust_decimal_
#[test]
fn rust_decimal_to_f64_agrees_on_fifteen_digit_mantissas_so_a_narrow_generator_is_vacuous() {
let narrow = 10i128.pow(15) - 1;
let result = run((-narrow..=narrow, 0u32..=15), 4096, true, |(m, s)| {
let result = run((-narrow..=narrow, 0u32..=15), 256, true, |(m, s)| {
let d = Decimal::from_i128_with_scale(m, s);
prop_assert_eq!(
crate_to_f64(&d).to_bits(),
@@ -772,7 +772,7 @@ fn the_accumulator_reads_the_exact_sum_or_its_stated_roundings() {
prop::collection::vec(weighted(term()), 0..24),
prop::collection::vec(weighted(pooled_term()), 0..40),
];
run(lists, 512, false, |xs| {
run(lists, 256, false, |xs| {
let got = sum_weighted(&xs);
let e = Expected::of(&xs);
let present = e.inexact.values().any(|w| *w != 0);
@@ -1004,7 +1004,7 @@ fn check_language(
parse: &dyn Fn(&str, Typing) -> Option<Num>,
deterministic: bool,
) -> Result<(), String> {
run(lexeme(), 512, deterministic, |s| {
run(lexeme(), 256, deterministic, |s| {
let gate = s.parse::<f64>().is_ok_and(f64::is_finite);
let parsed = parse(&s, Typing::Inferred);
prop_assert_eq!(
@@ -1205,7 +1205,7 @@ fn an_intermediate_beyond_i128_comes_back_exact() {
#[test]
fn the_canonical_text_reads_back_as_the_same_number() {
run(any_num(), 512, false, |n| {
run(any_num(), 256, false, |n| {
let text = n.to_string();
let back = Num::from_canonical(&text);
prop_assert!(