Skip to content

Dummies: cross-engine reachability suite + decimal full-range overflow fix - #274

Merged
Reefact merged 2 commits into
mainfrom
claude/issue-213-discussion-7t6rls
Jul 21, 2026
Merged

Dummies: cross-engine reachability suite + decimal full-range overflow fix#274
Reefact merged 2 commits into
mainfrom
claude/issue-213-discussion-7t6rls

Conversation

@Reefact

@Reefact Reefact commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Add a single parameterized reachability suite that runs a shared scenario battery against every interval-backed Dummies builder (#213), and fix the unconstrained AnyDecimal full-range OverflowException that suite surfaced. This closes the "membership-tested but reachability-blind" gap the 2026-07-20 audit named (§9.2/§9.3) — the blind spot that let #206 and #207 ship green.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring
  • Analyzer / diagnostic change
  • Tests
  • Documentation
  • Build / CI / tooling

Changes

  • Tests — add Dummies.UnitTests/CrossEngineReachabilityTests.cs: one [Theory] per scenario, run against every interval-backed builder (the 8 discrete integers, Int128/UInt128, Double/Single/Half, Decimal, and the five temporal types) through a per-type adapter — a new builder is one row in AllCases, not a new file. Scenarios: an unconstrained draw reaches both halves of its domain; a wide Between reaches both halves; both inclusive bounds are reachable (exactly for discrete types, to within 1% for continuous ones); a point excluded from a narrow range still generates and is never returned; OneOf then Except yields only the survivors; contradictory constraints throw naming both sides. Deterministic (one fixed seed, a fixed draw count); each builder is a serializable, individually-runnable theory row.
  • FixDummies/DecimalIntervalSpec.cs samples bounded decimals as a convex combination min*(1 - fraction) + max*fraction instead of mid ± half, which overflowed on the symmetric full domain and made unconstrained Any.Decimal().Generate() throw OverflowException. Bounded-range behaviour is unchanged (uniform, exclusion-nudged, reproducible within a version).
  • The dedicated Dummies: AnyDecimal never generates the upper half of a range #206 (DecimalBetweenReachesBothHalves) and Dummies: AnySingle/AnyHalf exclusion nudge stalls on satisfiable specs #207 (ContinuousExclusionNudgeTests) regressions are kept as focused, commented guards.

Scope note: the suite covers the interval-backed builders. The non-interval scalars (bool, guid, string, enum, char) are excluded — they expose no user-bounded ordered range, so "both halves / both endpoints" is undefined for them. This matches the issue's Direction ("numeric/temporal"); the acceptance criterion's "every scalar builder" was read down accordingly — flagging for confirmation.

Testing

  • dotnet build FirstClassErrors.sln
  • dotnet test FirstClassErrors.sln — all projects green; Dummies.UnitTests 351/351
  • Analyzer tests pass (FirstClassErrors.Analyzers.UnitTests — 132/132)

Guard validation: reintroducing the #206 fraction and the #207 static-ulp step was verified to turn the suite red (the #207 revert reddens Single/Half but not Double, whose quantize is the identity — the engine defect isolated to the affected facades), and reverting the decimal fix reddens the full-range Decimal scenario with the original OverflowException.

Documentation

  • Public API / error documentation updated
  • README / doc/ updated
  • French translation (doc/handwritten/for-users/README.fr.md) updated if user-facing behavior changed
  • No documentation change required

Architecture decisions

  • No architectural decision in this pull request

Related issues

Closes #213


🤖 Generated with Claude Code

https://claude.ai/code/session_01Tsv9tNCWpTENBTQUmpDUgP

claude added 2 commits July 21, 2026 16:44
DecimalIntervalSpec.Generate sampled a bounded draw as mid ± half around
the interval midpoint. On the unconstrained domain [decimal.MinValue,
decimal.MaxValue] that overflows: the domain is symmetric, so max/2 rounds
up and half = max/2 - min/2 doubles to just past decimal.MaxValue, throwing
an OverflowException. An unconstrained Any.Decimal().Generate() therefore
never returned a value at all — the whole advertised domain was
unreachable, a sibling of the #206 upper-half defect.

Interpolate as a convex combination instead: min*(1 - fraction) +
max*fraction stays within [min, max] for fraction in [0, 1], and no
intermediate ever leaves the decimal range. Bounded ranges are unchanged
in behaviour (still uniform across [min, max], still nudged off exclusions,
still reproducible within a version); only the full-range crash is fixed.

Surfaced by the cross-engine reachability suite added for #213, whose
full-range scenario exercises every builder's unconstrained domain — the
one draw no existing test performed for decimal.

Refs: #213
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tsv9tNCWpTENBTQUmpDUgP
The Dummies tests asserted membership (a generated value satisfies its
constraints) but never reachability (the whole declared domain is
generable). That blind spot let two defects ship green — AnyDecimal never
reaching the upper half of a range (#206) and the AnySingle/AnyHalf
exclusion nudge stalling on satisfiable specs (#207) — and no test ran the
same scenario across every builder, so an engine-level regression could
hide in the one type-facade a hand-written test happened not to cover.

Add one parameterized suite that runs a shared battery against every
interval-backed builder (the discrete integers, the two 128-bit integers,
the binary-floating trio, decimal, and the five temporal types) through a
small per-type adapter. A new builder is covered by adding one row to
AllCases, not a new file. Each builder is a serializable theory row, so it
shows and re-runs as an isolated test. Scenarios: an unconstrained draw
reaches both halves of its domain; a wide Between reaches both halves; both
inclusive bounds are reachable (exactly for discrete types, to within 1%
for continuous ones); a point excluded from a narrow range still generates
and is never returned; OneOf then Except yields only the survivors;
contradictory constraints throw naming both sides.

The suite is deterministic: one fixed seed, a fixed draw count large enough
that a correct uniform generator reaches the asserted region while a stuck
one fails every time — a stable CI guard, not a flaky one. Reintroducing
the #206 fraction and the #207 static-ulp step was verified to turn it red
(the #207 revert reddens Single/Half but not Double, whose quantize is the
identity — the engine defect isolated to the affected facades). The
dedicated #206 and #207 regressions are kept as focused, commented guards.

Refs: #213
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tsv9tNCWpTENBTQUmpDUgP
@Reefact Reefact changed the title fix(dummies): sample decimals without overflowing on the full range Dummies: cross-engine reachability suite + decimal full-range overflow fix Jul 21, 2026
@Reefact
Reefact merged commit 33b8090 into main Jul 21, 2026
15 checks passed
@Reefact
Reefact deleted the claude/issue-213-discussion-7t6rls branch July 21, 2026 18:45
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.

Dummies: add reachability tests and a cross-engine scenario suite

2 participants