Skip to content

IsUuidV7 - #73

Merged
feO2x merged 5 commits into
mainfrom
72-is-uuidv7
Aug 2, 2026
Merged

IsUuidV7#73
feO2x merged 5 commits into
mainfrom
72-is-uuidv7

Conversation

@feO2x

@feO2x feO2x commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Closes #72

feO2x and others added 5 commits August 2, 2026 14:58
Check<Guid> offers only IsEmpty/IsNotEmpty, so a service accepting a
client-generated identifier cannot state that it must be a UUIDv7. A v4
GUID from a misconfigured client is accepted and surfaces later as index
fragmentation.

Key decisions recorded in the plan:

- Require both the version nibble (7) and the RFC 9562 variant bits (10).
  Guid.Version reports the version regardless of the variant, so a
  version-only test accepts values Guid.CreateVersion7 cannot produce.
- Read both fields by reinterpreting the Guid over a field overlay with
  Unsafe.As, rather than through ToByteArray or TryWriteBytes. This is
  allocation-free on both target frameworks and, more importantly,
  removes a per-target byte index: Guid's default order is mixed-endian,
  which would put the version nibble at index 7 on netstandard2.0 and 6
  in a big-endian span, an off-by-one the net10.0-only suite could not
  catch.
- Mirror the identical GuidFields overlay already shipping in
  CanonicalTextFormatter, including its narrow CS0649 suppression, which
  TreatWarningsAsErrors makes mandatory. The layout assumption is already
  load-bearing in the core library rather than new to this change.
- Treat Guid.Version and Guid.Variant as the test oracle, not the
  implementation. netstandard2.0 has neither, so using them would
  reintroduce the per-target split the overlay exists to avoid.
- Verify with an exhaustive 16x16 version/variant nibble matrix against
  that oracle, asserting the accepted count of 4 of 256. This pins both
  offsets and both masks, and replaces hand-picked boundary values and a
  random sample.
- Give the invariant one name on two receivers: public
  GuidExtensions.IsUuidV7(Guid) alongside Checks.IsUuidV7(Check<Guid>),
  keeping Checks the home of Check<T> extensions.
- Move release notes in both Validation and Validation.OpenApi: the
  built-in contract registry's key set is public behavior even though
  that package's source barely changes.
- Defer timestamp plausibility, Check<Guid?> overloads, and a generalized
  IsUuidVersion(int).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9QDDRWbDXTrE12S6ErBt4
Tighten the IsUuidV7 plan from 231 to 192 lines. All nine acceptance
criteria and every normative instruction are preserved; the reduction is
redundant prose, chiefly in the Predicate section, where the rejection of
each alternative, the layout justification, and the endianness argument
each restated points the others had already made.

Also correct a stale count: the registration points list says six places
rather than five, which is what it has enumerated since the shared
BuiltInValidationErrorDefinitions.UuidV7 property was split out from the
definition class.

Restore one fact the condensation had dropped: Guid.Version arrived in
.NET 9, which is why the oracle is available to the net10.0-only test
project but not to the netstandard2.0 implementation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9QDDRWbDXTrE12S6ErBt4
Signed-off-by: Kenny Pflug <kenny.pflug@live.de>
Add IsUuidV7 to Check<Guid> in both the built-in-message and
ErrorOverrides overloads, backed by the new UuidV7 error code, a
customizable ValidationErrorTemplates.UuidV7 template, and a
metadata-free OpenAPI contract registered for the code.

Expose the invariant standalone as public GuidExtensions.IsUuidV7 so the
bit manipulation lives in one place and callers can guard the same rule
outside a check chain. The predicate reinterprets the Guid over a field
overlay mirroring CanonicalTextFormatter's, which serves both target
frameworks without conditional compilation and allocates nothing on the
passing path (measured: 0 bytes over 1,000,000 calls).

Check both RFC 9562 fields, not just the version: a version-7 value
carrying a non-RFC variant cannot be produced by Guid.CreateVersion7 and
must fail. An exhaustive 16x16 version-nibble by variant-nibble matrix
pins both offsets and both masks against an oracle built from Guid.Version
and Guid.Variant, and asserts that exactly the four version-7 by variant
8-b combinations are accepted.

Closes #72

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9QDDRWbDXTrE12S6ErBt4
Add UuidV7 to the two registry-style suites that enumerate every built-in
error definition: the stable-provider test, which contributes the
BeSameAs assertion on ErrorTemplates.UuidV7 that UuidV7ValidationTests
never made directly, and the ProvideMessage family. Those lists are what
the next person adding a definition reads as the checklist, so leaving
UuidV7 out of them was a consistency gap even though coverage was
already complete.

Rename the stable-provider test to name the Guid family. It is
partitioned against ComparableDefinitions_ShouldExposeStableProviders,
so the enumeration in its name has to stay honest.

Record why the RFC-derived accepted set is not redundant with the
version-by-variant matrix. Guid.Version and Guid.Variant compute the
same two expressions the predicate evaluates, so the matrix pins the
field overlay's offsets but cannot pin the masks; only the hardcoded
accepted set does that. Both tests walk the same 256 inputs, which
invites deleting one of them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9QDDRWbDXTrE12S6ErBt4
@feO2x feO2x self-assigned this Aug 2, 2026
@feO2x feO2x added the enhancement New feature or request label Aug 2, 2026
@feO2x feO2x linked an issue Aug 2, 2026 that may be closed by this pull request
9 tasks
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Code Coverage

Package Line Rate Branch Rate Complexity Health
Light.PortableResults 98% 94% 3219
Light.PortableResults.AspNetCore.MinimalApis 89% 75% 25
Light.PortableResults.AspNetCore.Mvc 89% 75% 25
Light.PortableResults.AspNetCore.OpenApi 94% 83% 505
Light.PortableResults.AspNetCore.Shared 100% 100% 28
Light.PortableResults.Validation 97% 89% 2981
Light.PortableResults.Validation.OpenApi 98% 91% 146
Light.PortableResults.Validation.OpenApi.SourceGeneration 92% 86% 1164
Summary 96% (14862 / 15452) 90% (6262 / 6926) 8093

Minimum allowed line rate is 60%

@feO2x
feO2x merged commit 2bf882b into main Aug 2, 2026
2 checks passed
@feO2x
feO2x deleted the 72-is-uuidv7 branch August 2, 2026 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an IsUuidV7 assertion to the validation library

1 participant