DateTime Assertions - #76
Merged
Merged
Conversation
Plan IsUtc, IsLocal, and IsUnspecified for Check<DateTime>, following the IsUuidV7 shape: three metadata-free error codes, three customizable templates, and three built-in OpenAPI contracts. Named assertions rather than one parameterized HasKind, matching how IsEmpty/IsNotEmpty and IsNull/IsNotNull are split today. State the contract as the kind and nothing more: IsUtc accepts exactly those normalized values whose Kind is DateTimeKind.Utc. The predicate cannot observe where a value came from, so the plan keeps that separate from the System.Text.Json consequence, which is that a trailing Z is required and 2026-08-02T10:00:00+00:00 arrives as Local and is rejected despite denoting the same instant - measured on .NET 10, where the converter resolves every explicit offset against the server's time zone before the DTO exists. That consequence is real and belongs in the README and the XML remarks, because it is the actionable form for an API consumer, but it is false for a value arriving over gRPC or produced by DateTime.UtcNow. The message reads "must be represented in UTC" for the same reason: "must be in UTC" describes the instant and reads as already satisfied on a +00:00 payload, while naming the Z encoding would claim knowledge the assertion does not have. Drop the Check<DateTimeOffset> overload the first draft shared the Utc code with. DateTimeOffset has no kind, so the assertion would test Offset == TimeSpan.Zero, which accepts +00:00 that the DateTime overload rejects, and OpenAPI cannot expose the difference because both types map to string/date-time. An unzoned wire value also arrives carrying the server's own offset, which would make the verdict depend on the host's time zone. Moved to #74 as a separate ZeroOffset candidate. Correct two further claims the first draft got wrong. Check<T> is constructed after the context-wide or per-check IValueNormalizer runs, so these assertions inspect the normalized value; the default TrimStringNormalizer preserves non-strings, but that is a default rather than a guarantee. And there is no generator diagnostic for an unregistered error code - document construction fails at runtime instead - so the OpenAPI criterion has to be verified by generating a document. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019vu3qgcqGWGr2TddYEpLpW
Cut the plan roughly in half, mostly by removing justification prose that ai-plans/AGENTS.md asks plans not to carry: explanations of routine implementation work and background a senior engineer already has. The three-section structure, every acceptance criterion, and every decision survive. Restore four items the first pass dropped that are decisions rather than prose. Chief among them, why the wire-format test is not redundant with the 3x3 kind matrix: it walks the same ground, so without a stated reason it reads as duplication and gets deleted, when it is really a regression detector for System.Text.Json behavior that the whole feature rests on. The 0072 plan needed the same note for its RFC-derived accepted set against its version-by-variant matrix. Also restore both rejected message wordings, since "must be represented in UTC" took two review rounds to reach and half the reasoning made reverting it to "must be in UTC" look like a simplification; why TryGetStableMessageProvider applies here, so a later parameterized rule in this family does not copy it blindly; and the note that the wire-format table was measured rather than assumed, with only the kind being host-independent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019vu3qgcqGWGr2TddYEpLpW
Signed-off-by: Kenny Pflug <kenny.pflug@live.de>
- Restore the indentation of the closing PackageReleaseNotes tag and use ASCII hyphens in the notes, matching the sibling packages. - Say that DateTime.SpecifyKind and friends *can* produce Utc, as the XML remarks already do, instead of claiming they always do. - Scope the JSON round-trip DTO to its file so it no longer occupies a name in the shared test namespace. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019vu3qgcqGWGr2TddYEpLpW Signed-off-by: Kenny Pflug <kenny.pflug@live.de>
8 tasks
Minimum allowed line rate is |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #75