Skip to content

feat(justdummies): guard public/internal arguments against null - #322

Merged
Reefact merged 2 commits into
mainfrom
claude/null-validation-constructors-6f8pbe
Jul 27, 2026
Merged

feat(justdummies): guard public/internal arguments against null#322
Reefact merged 2 commits into
mainfrom
claude/null-validation-constructors-6f8pbe

Conversation

@Reefact

@Reefact Reefact commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

Every public/internal member of JustDummies now rejects a null non-nullable reference-type argument with an ArgumentNullException naming the parameter, so a null fails fast at the boundary instead of surfacing later as a NullReferenceException. A reflection-driven convention test enforces this across the whole surface and holds new members to it automatically.

Type of change

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

Changes

  • Add null-argument guards (if (x is null) { throw new ArgumentNullException(nameof(x)); }) to every public/internal constructor and method taking a non-nullable reference-type parameter, across all of JustDummies.
  • Scope respected: private members are trusted (their inputs are guarded at the public/internal boundary they enter through, e.g. the Create(RandomSource) factories); value-type and nullable (?) parameters are left as-is (a ? parameter's contract permits null).
  • Exempt exception-type constructors: they run on the error-handling/logging path, where throwing over a null message would mask the original failure.
  • Any.ReproduciblyAsync now validates body synchronously instead of deferring the guard into the returned task.
  • Add NullArgumentGuardConventionTests: a reflection test that enumerates the whole public/internal surface and asserts each non-nullable reference parameter throws ArgumentNullException; it covers new members automatically and fails loudly on any parameter it cannot exercise. Excluded from the net472 floor (it uses NullabilityInfoContext, a .NET 6+ API); the guards themselves remain netstandard2.0.
  • Open the library's internals to the contract suite (InternalsVisibleTo) so the convention can verify the internal boundary the public API can never route a null through.
  • Record the decision as ADR-0045 (EN + FR), indexed.

Testing

  • dotnet build FirstClassErrors.sln — 0 warnings / 0 errors.
  • dotnet test FirstClassErrors.sln — not run in full; the suites below were run instead.
  • Analyzer tests pass (FirstClassErrors.Analyzers.UnitTests) — not run.

Suites actually run (all green):

  • dotnet test JustDummies.UnitTests — 556 passed (including the new convention test).
  • dotnet test JustDummies.PropertyTests — 220 passed.
  • dotnet test FirstClassErrors.Testing.UnitTests — 8 passed (consumer via ADR-0026).
  • dotnet test JustDummies.Xunit.UnitTests — 14 passed.
  • net472 support-floor build, Release, EnableNet472Floor=true (JustDummies.UnitTests + JustDummies.PropertyTests) — 0 / 0.

Documentation

  • Public API / error documentation updated — no public API change (signatures unchanged; async is an implementation detail).
  • README / doc/ updated — ADR-0045 added (EN + FR) and indexed.
  • French translation (doc/handwritten/for-users/README.fr.md) — not needed (no user-facing README behavior change).
  • No documentation change required

Architecture decisions

  • No architectural decision in this pull request
  • New decision recorded — ADR-0045 (accepted by the maintainer in-session; opens InternalsVisibleTo, deliberately relaxing the previously black-box test posture recorded in the 2026-07-20 audit §9.3).

Related issues

None.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KR3opZZYgSiomTKWvC11q8


Generated by Claude Code

claude added 2 commits July 27, 2026 16:26
Every public or internal member — constructor or method — now rejects a
null non-nullable reference-type argument with an ArgumentNullException
naming the parameter. The class, not the assembly, is the trust boundary:
a member validates what crosses it (including the internal Create factories
and constructors the public API can never route a null through), and trusts
what a validating member already accepted, so a null fails fast instead of
surfacing later as a NullReferenceException far from its cause.

Exception-type constructors are exempt: they run on the error-handling and
logging path, where throwing over a null message would mask the original
failure.

A reflection-driven convention test (NullArgumentGuardConventionTests)
enforces this across the whole surface and holds new members to it
automatically. Verifying the internal boundary requires internal access, so
InternalsVisibleTo is opened to the contract suite, deliberately relaxing
the previously black-box test posture. ReproduciblyAsync now validates its
body synchronously rather than deferring the guard into the returned task.

Decision recorded in ADR-0045 (Proposed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KR3opZZYgSiomTKWvC11q8
The maintainer accepted the null-argument guard convention; flip ADR-0045
(and its French translation and the index) from Proposed to Accepted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KR3opZZYgSiomTKWvC11q8
@Reefact
Reefact merged commit df4a6c1 into main Jul 27, 2026
27 of 28 checks passed
@Reefact
Reefact deleted the claude/null-validation-constructors-6f8pbe branch July 27, 2026 16:37
Reefact pushed a commit that referenced this pull request Jul 27, 2026
Reconcile the out-of-order-disposal fix with ADR-0045 (guard public and
internal arguments against null), which landed on main via #322.

* AmbientState constructor: main added a null guard on `random`; this branch
  added a `parent` parameter to the same constructor — keep both.
* SeedScope: bring its new internal constructor under the same convention by
  guarding its non-nullable `frame` argument, matching the guard #322 applied
  to AmbientState.

The reflection-driven NullArgumentGuardConventionTests added by #322 passes
against the merged code.
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