Skip to content

Result Default Guard - #81

Merged
feO2x merged 4 commits into
mainfrom
80-result-default-guard
Aug 4, 2026
Merged

Result Default Guard#81
feO2x merged 4 commits into
mainfrom
80-result-default-guard

Conversation

@feO2x

@feO2x feO2x commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes #80

feO2x and others added 4 commits August 3, 2026 22:22
A result that is invalid while carrying no errors is neither a success
nor a failure. Writing it over CloudEvents emitted a failure payload
with an empty errors array that this library's own reader rejects, and
the HTTP paths failed only incidentally, with messages naming neither
the result nor the default instance.

Every public API that consumes a result in order to write it out now
routes through the new ResultObjectExtensions.MustNotBeDefaultInstance
guard clause, which throws one ArgumentException naming the default
instance as the cause and Result.Ok/Result.Fail as the remedy. This
covers both sites per transport, so the guard cannot be bypassed by
constructing the public wrapper structs directly.

Note that only Result<T> with a reference type or a nullable value type
can take that shape: Result encapsulates a Result<Unit>, and IsValid
tests _value is not null, which a value type always satisfies. The
guards on the Result-typed sites are therefore unreachable today and
are kept for uniformity - see ai-plans/0080-1-plan-deviations.md.

Closes #80

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WwGeQai3zfz6wYLeNQx8Ag
Both notes in "Here is Your Space" moved to where the knowledge is used,
leaving the section empty for the next round of notes.

Why the two evaluation catch filters in MetadataValueReconstructor
exclude OperationCanceledException is now a comment at both filters: an
aborted generation pass must propagate rather than be downgraded to an
unsupported value. That the contract is not observable through the
generator's public surface is a blind spot, so it joins the other "do
not read as adequate coverage" entries in tests/AGENTS.md, naming the
trigger that would make it testable.

A README.md for the source generator project was considered and
rejected for now; the reasoning is in the plan deviations file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WwGeQai3zfz6wYLeNQx8Ag
Document the exact invalid-without-errors predicate and identify a default instance as its usual source, so custom IResultObject values are not mislabeled.

Strengthen the tests with genuinely non-default custom structs and correct the deviations record's housekeeping history.
@feO2x feO2x self-assigned this Aug 4, 2026
@feO2x feO2x added the bug Something isn't working label Aug 4, 2026
@feO2x feO2x linked an issue Aug 4, 2026 that may be closed by this pull request
10 tasks
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Code Coverage

Package Line Rate Branch Rate Complexity Health
Light.PortableResults 98% 95% 3567
Light.PortableResults.AspNetCore.MinimalApis 100% 100% 33
Light.PortableResults.AspNetCore.Mvc 100% 100% 33
Light.PortableResults.AspNetCore.OpenApi 94% 83% 505
Light.PortableResults.AspNetCore.Shared 100% 100% 28
Light.PortableResults.Validation 97% 89% 3050
Light.PortableResults.Validation.OpenApi 98% 91% 146
Light.PortableResults.Validation.OpenApi.SourceGeneration 92% 86% 1164
Summary 97% (15665 / 16233) 91% (6640 / 7304) 8526

Minimum allowed line rate is 60%

@feO2x
feO2x merged commit 54b6c4b into main Aug 4, 2026
3 checks passed
@feO2x
feO2x deleted the 80-result-default-guard branch August 4, 2026 04:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Guard against default result instances at the write boundaries

1 participant