Skip to content

feat(dummies): add the Any.Uri() family of URI generators#295

Merged
Reefact merged 3 commits into
mainfrom
claude/issue-226-uri-family
Jul 23, 2026
Merged

feat(dummies): add the Any.Uri() family of URI generators#295
Reefact merged 3 commits into
mainfrom
claude/issue-226-uri-family

Conversation

@Reefact

@Reefact Reefact commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

Add Any.Uri(), an arbitrary-yet-valid System.Uri generator organised as a typed family. The unconstrained root spans the safe URI space — an absolute web (http/https), WebSocket (ws/wss), FTP or mailto URI, or a relative reference — and each narrowing (Web/WebSocket/Ftp/Mailto/Relative) returns a family-specific builder exposing only that family's valid components, so an impossible combination (a port on a mailto, a fragment on a WebSocket) cannot even be written. One item of the demand-driven Nice-to-Have backlog.

Type of change

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

Changes

  • Add Any.Uri()AnyUri root with family narrowings Web()/WebSocket()/Ftp()/Mailto()/Relative(), each returning a typed builder (AnyWebUri, AnyWebSocketUri, AnyFtpUri, AnyMailtoUri, AnyRelativeUri) that exposes exactly that family's RFC-valid components (e.g. AnyWebSocketUri has no user-info/fragment per RFC 6455; AnyMailtoUri has no port).
  • Every component is drawn from ASCII-unreserved characters and the URI is assembled directly — valid by construction (never generated then filtered) and reproducible under a seed on every target framework.
  • Reject IDN hosts and non-canonical shorthand-IPv4 hosts (both would not round-trip identically across frameworks — the same determinism hazard); keep the file scheme out of the unconstrained draw, the way Any.Double() keeps NaN and the infinities out of its default draw.
  • Mirror the factory on AnyContext, declare the surface in both per-TFM public-API baselines, and document it in the package README and XML docs.

Testing

  • dotnet build FirstClassErrors.sln
  • dotnet test FirstClassErrors.sln
  • Analyzer tests pass (FirstClassErrors.Analyzers.UnitTests)

Full solution: 10 test projects, 0 failures (Dummies.UnitTests 494). Coverage: per-family valid-by-construction fuzzing, scheme and family reachability, the conflict cases, argument validation (IDN and non-canonical host rejection, port and segment bounds), the degenerate-relative case, and seeded reproducibility. Additionally validated by a multi-agent adversarial pass (~5.7M fuzzed generations plus RFC-surface, API-honesty and code-review agents); every real finding it surfaced (single-arg user-info password, shorthand-IPv4 host, degenerate 0-segment relative, culture-invariant path label) is fixed in this commit.

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 Dummies package README and the XML docs are updated. The for-users README.fr.md documents FirstClassErrors, not the Dummies constraint surface (the Dummies user guide is tracked separately), so no French translation applies here.

Architecture decisions

This PR establishes the typed-progression API pattern — a builder that changes type and surface as it narrows — which is distinct from every other (flat, runtime-conflict) builder in the library. Rationale: URIs span structurally different shapes (authority vs mailto vs relative), so category errors (Mailto().WithPort()) are made unrepresentable at compile time, whereas value-dependent conflicts (as in AnyString) can only be runtime. Per the maintainer's decision this is not recorded as an ADR yet; flagged here so it can become a Proposed ADR if desired.

Related issues

Refs #226

🤖 Generated with Claude Code

https://claude.ai/code/session_01FPAdCRsiaVo2orjJwCaDnb


Generated by Claude Code

claude and others added 3 commits July 23, 2026 12:09
Add Any.Uri(), an arbitrary-yet-valid System.Uri generator organised as a
typed family. The unconstrained root spans the safe URI space — an absolute
web (http/https), WebSocket (ws/wss), FTP or mailto URI, or a relative
reference — and each narrowing (Web/WebSocket/Ftp/Mailto/Relative) returns a
family-specific builder that exposes only that family's valid components, so
an impossible combination (a port on a mailto, a fragment on a WebSocket)
cannot be written rather than being caught at run time.

Every component is drawn from ASCII-unreserved characters and the URI is
assembled directly, so a value is valid by construction — never generated
then filtered — and reproducible under a seed on every target framework.
Internationalized (IDN) hosts are rejected (pass punycode) and the file
scheme is kept out of the unconstrained draw, because a platform-dependent
path would not round-trip identically across frameworks — the way
Any.Double() keeps NaN and the infinities out of its default draw.

Mirror the factory on AnyContext, declare the surface in both per-TFM public
API baselines, and cover it with per-family valid-by-construction fuzzing,
scheme and family reachability, the conflict cases, argument validation (IDN
rejection, port and segment bounds) and seeded reproducibility.

Refs: #226
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FPAdCRsiaVo2orjJwCaDnb
Two fixes for the not-yet-shipped Any.Uri family so it builds and validates
identically down to the net472 floor:

- AnyUriTests used string.Split(char, StringSplitOptions), an overload that
  only exists on .NET Core; switch to the char[] overload so the test
  compiles on net472.
- RequireHost rejected shorthand-IPv4 hosts by round-tripping the host
  through System.Uri, whose shorthand parsing is itself what differs across
  target frameworks — so the guard was fragile in the same way as the input
  it rejects. Replace it with a framework-independent dotted-quad check
  (IsCanonicalIpv4) that never touches System.Uri.

Refs: #226
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FPAdCRsiaVo2orjJwCaDnb
@Reefact
Reefact merged commit 8f4c682 into main Jul 23, 2026
16 checks passed
@Reefact
Reefact deleted the claude/issue-226-uri-family branch July 23, 2026 13: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.

2 participants