Skip to content

feat(justdummies): add JD016-JD017 for collection and enum constraints - #372

Merged
Reefact merged 1 commit into
mainfrom
claude/justdummies-analyzers-analysis-z9q1xd
Jul 29, 2026
Merged

feat(justdummies): add JD016-JD017 for collection and enum constraints#372
Reefact merged 1 commit into
mainfrom
claude/justdummies-analyzers-analysis-z9q1xd

Conversation

@Reefact

@Reefact Reefact commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

Continues the JustDummies.Constraints category with the collection and enum surfaces, both built on the helpers #371 landed.

Type of change

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

Changes

  • JD016 CollectionConstraintsAdmitNoValue (Warning) — count constraints that cannot all hold (WithCount(0).NonEmpty(), WithMinCount(5).WithMaxCount(2), more Containing items than the cap allows), and the cardinality gate ADR-0013 records: a distinct collection asking for more elements than its element generator can produce.
  • JD017 EnumUniverseViolation (Warning) — an enum constraint outside the declared members: a [Flags] combination without AllowingCombinations(), an undeclared numeric value, or an exclusion that empties the universe.
  • 28 new analyzer tests (153 total), 4 documentation pages (EN + FR), both index tables, release-tracking rows.

Both throw at declaration time, so these move an arrange-time red to a build-time red rather than closing a silent green. That is still worth it: the chain usually sits in an arrange helper several call frames away from the test that dies on it, where the message names two constraints the reader must go hunting for.

Why the enum surface is its own rule

Its domain is metadata — the declared members — rather than interval arithmetic, and its mistake has a distinct model: a value outside the declared set is not a narrowing that happens to be empty, it is a category error. The [Flags] case gets its own hint in the message, because AllowingCombinations() is not something a reader would guess from "not a declared member".

Dogfooding corrected the cardinality helper

Twelve behaviours were probed against the built library before either rule was written — count contradictions, the Containing overflow, the SetOf(Boolean) and Distinct() cardinality gates, the enum universe in all four shapes. All twelve matched the design.

Dogfooding then found what the probe had not covered: AllowingCombinations() widens an enum's universe to the OR-closure of its declared members — eight values for four flags — and my helper walked the element chain to its factory and counted declared members, condemning Any.SetOf(Any.Enum<Permissions>().AllowingCombinations()).WithCount(8), which AnyEnumCombinationTests asserts succeeds.

The helper now stands down when it sees that constraint rather than computing the closure. Its own doc comment already said an unprovable domain must never be treated as a small one; I had violated that by looking only at the factory. A deliberate false negative is the right side to err on, and two tests now pin both directions — the widened chain stays silent, the un-widened one still reports.

After the fix, JD016 and JD017 produce zero hits across JustDummies.UnitTests, JustDummies.PropertyTests, JustDummies.Xunit.UnitTests, FirstClassErrors.Testing.UnitTests and FirstClassErrors.UnitTests.

Testing

  • dotnet build FirstClassErrors.sln — 0 warnings, 0 errors
  • dotnet test FirstClassErrors.sln — 2 070 tests, 0 failures across all 13 test projects
  • Analyzer tests pass (FirstClassErrors.Analyzers.UnitTests, 132) — the rules added here live in JustDummies.Analyzers.UnitTests (153)

Mutation testing was not run locally.

Documentation

  • Public API / error documentation updated — no public API change
  • README / doc/ updated — JD016/JD017 pages and the rule index
  • French translation updated — JD016.fr.md, JD017.fr.md and the French index
  • No documentation change required

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-____

JD016 applies ADR-0013's cardinality gate at build time rather than deciding anything about it; JD017 applies ADR-0041's opt-in for flag combinations the same way.

Remaining

Thirteen catalogued rules: the scalar-chain emptiness test, no-effect constraints, duplicate pool values, the empty relative URI, the unused Combine operand, Distinct over reference equality, and the reproducibility long tail (nested scopes, committed replay seeds, parallel draws, shared static contexts, blank replay snippets). The two that carry their own decision are still waiting on you — the unsupported-regex rule needs the grammar shared with the library, and the production-code rule needs the IsTestProject MSBuild oracle.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GKqyhG9Y4AfdxEYekP2Evq


Generated by Claude Code

JD016 reports a collection chain whose constant count constraints cannot
all hold, or which asks for more distinct elements than its element
generator can produce — the cardinality gate ADR-0013 records. Both throw
at declaration time, so this moves an arrange-time red to a build-time
red rather than closing a silent green; the chain usually sits in a
helper several call frames from the test that dies on it.

JD017 keeps the enum surface separate, because its domain is metadata —
the declared members — rather than interval arithmetic, and its mistake
has its own model. Any.Enum draws only declared members, which is
deliberate and surprising in one place: on a [Flags] enum, writing a
combination in OneOf is the natural gesture and the generator refuses it
unless AllowingCombinations() is declared, so the message carries that
hint rather than leaving it to be guessed.

Twelve behaviours were probed against the built library before either
rule was written, and dogfooding then corrected the cardinality helper.
AllowingCombinations() WIDENS an enum's universe to the OR-closure of its
declared members — eight values for four flags — so counting declared
members condemned a chain AnyEnumCombinationTests asserts is legal. The
helper now stands down when it sees that constraint rather than
computing the closure: an unprovable domain must never be treated as a
small one, and a deliberate false negative is the right side to err on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKqyhG9Y4AfdxEYekP2Evq
@Reefact
Reefact merged commit 9367eee into main Jul 29, 2026
28 checks passed
@Reefact
Reefact deleted the claude/justdummies-analyzers-analysis-z9q1xd branch July 29, 2026 15:42
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