Skip to content

fix(dummies): honour narrow-range exclusions with a type-aware nudge - #270

Merged
Reefact merged 2 commits into
mainfrom
claude/issue-207-i55odl
Jul 21, 2026
Merged

fix(dummies): honour narrow-range exclusions with a type-aware nudge#270
Reefact merged 2 commits into
mainfrom
claude/issue-207-i55odl

Conversation

@Reefact

@Reefact Reefact commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

On the narrow (quantized) floating-point generators (AnySingle, AnyHalf), an exclusion inside a tight range made a satisfiable specification throw AnyGenerationException for a large fraction of seeds. The exclusion nudge in ContinuousIntervalSpec.Generate stepped with the static double-space NextUp instead of the type-aware _nextUp ladder, so one double ulp above a representable float/Half re-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

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

Changes

  • ContinuousIntervalSpec.Generate now nudges a colliding draw with the type-aware ladder (_nextUp) instead of the static double-space NextUp, so a step lands on the next representable value of the generator's own type.
  • The nudge is bidirectional: it walks ascending first, then descending from the original draw when the ascending walk leaves the bounds (new NudgeToFree helper). An exclusion on either bound of a tight range is now honoured — previously only an exclusion below the drawn value could be resolved.
  • The range guard is meaningful again: the next value is checked against _min/_max before 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).
  • Added Dummies.UnitTests/ContinuousExclusionNudgeTests.cs (6 tests).

Testing

  • dotnet build FirstClassErrors.sln
  • dotnet test FirstClassErrors.sln
  • Analyzer tests pass (FirstClassErrors.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 seeded AnyGenerationException, and seeded reproducibility.

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

The public contract is unchanged (Except/DifferentFrom never 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 internal InvalidOperationException detail referenced nowhere.

Architecture decisions

  • No architectural decision in this pull request
  • New decision recorded — ADR drafted as Proposed: ADR-____
  • Supersedes an existing ADR — successor proposed, status not flipped: ADR-____
  • ⚠️ Conflicts with an existing ADR — flagged for the maintainer: 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

claude and others added 2 commits July 21, 2026 14:36
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
Reefact enabled auto-merge July 21, 2026 14:46
@Reefact
Reefact merged commit 45b7e6c into main Jul 21, 2026
15 checks passed
@Reefact
Reefact deleted the claude/issue-207-i55odl branch July 21, 2026 14:50
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: AnySingle/AnyHalf exclusion nudge stalls on satisfiable specs

2 participants