fix(dummies): honour narrow-range exclusions with a type-aware nudge - #270
Merged
Conversation
When a draw collided with an excluded point, ContinuousIntervalSpec stepped with the static double-space NextUp instead of the type-aware _nextUp lambda. On Single and Half one double ulp above a representable value re-quantizes to the same value, so the walk stalled and a satisfiable specification exhausted the nudge budget and threw AnyGenerationException. AnyDouble was immune only because its quantize and nextUp are the identity. Step with the type-aware ladder and walk both directions: ascending first, then descending from the original draw when the ascending walk leaves the bounds, so an exclusion on either bound of a tight range is honoured. Check the next value against the bounds before clamping, so a genuinely exhausted range fails as a real "no value remains" condition rather than by budget exhaustion alone. Add regression tests per continuous type (Single, Half, Double) covering an exclusion inside a narrow range on either bound, a fully excluded range that must still throw a seeded AnyGenerationException, and seeded reproducibility. Refs: #207 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wCNSRakgsbJXCVcVDNv87
Reefact
enabled auto-merge
July 21, 2026 14:46
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On the narrow (quantized) floating-point generators (
AnySingle,AnyHalf), an exclusion inside a tight range made a satisfiable specification throwAnyGenerationExceptionfor a large fraction of seeds. The exclusion nudge inContinuousIntervalSpec.Generatestepped with the static double-spaceNextUpinstead of the type-aware_nextUpladder, so onedoubleulp above a representablefloat/Halfre-quantized to the same value and the walk stalled until the budget burned out. This fixes the nudge and makes it walk both directions.Type of change
Changes
ContinuousIntervalSpec.Generatenow nudges a colliding draw with the type-aware ladder (_nextUp) instead of the static double-spaceNextUp, so a step lands on the next representable value of the generator's own type.NudgeToFreehelper). An exclusion on either bound of a tight range is now honoured — previously only an exclusion below the drawn value could be resolved._min/_maxbefore clamping, so a genuinely exhausted range fails as a real "no representable value in range remains" condition rather than by budget exhaustion alone (the budget stays only as a backstop).Dummies.UnitTests/ContinuousExclusionNudgeTests.cs(6 tests).Testing
dotnet build FirstClassErrors.slndotnet test FirstClassErrors.slnFirstClassErrors.Analyzers.UnitTests)All test projects green on the rebased branch (
Dummies.UnitTests: 229). The new regression tests were also confirmed to fail without the source fix (4 of 6, with the pre-fix exception) and pass with it. Coverage per continuous type (AnySingle,AnyHalf,AnyDouble): an exclusion inside a narrow range on either bound, a fully excluded range that must still throw a seededAnyGenerationException, and seeded reproducibility.Documentation
doc/updateddoc/handwritten/for-users/README.fr.md) updated if user-facing behavior changedThe public contract is unchanged (
Except/DifferentFromnever yield the excluded value) — this only makes the engine honour it where it previously threw. No user-facing doc described the nudge, and the changed message is an internalInvalidOperationExceptiondetail referenced nowhere.Architecture decisions
Proposed: ADR-____The fix is an implementation detail of an internal engine; the "a satisfiable specification produces a value" contract already existed.
Related issues
Closes #207
🤖 Generated with Claude Code
https://claude.ai/code/session_016wCNSRakgsbJXCVcVDNv87
Generated by Claude Code