Problem
Three symmetry gaps force ceremony the ADRs elsewhere removed. (a) Non-generic Outcome lacks the ADR-0003 value-mapping Then: producing a value after a void command requires outcome.Then(() => Outcome<X>.Success(v)) — precisely the shape ADR-0003 eliminated on Outcome<T>. (b) PrimaryPortError/SecondaryPortError lack the single-inner-error Create overload that DomainError and InfrastructureError both have — wrapping ONE domain error (the most common boundary case) requires new PrimaryPortInnerErrors().Add(error). (c) ErrorContext.TryGet<T> has no [NotNullWhen(true)], so NRT consumers must null-forgive after a true return; the standard netstandard2.0 mitigation (internally declared flow attributes) is applied nowhere.
Impact
First-week friction in an API that has taught users to expect symmetry; all three are additive and cheap only until v1.
Direction
Outcome.Then<TResult>(Func<TResult>) (+ async twin), proven safe by the same overload-betterness argument as ADR-0003, with the lock-in proof added to OutcomeThenOverloadResolutionTests.
PrimaryPortError.Create(code, msg, [transience,] DomainError innerError, …) and the SecondaryPortError twin.
- Embed the compiler-recognized
System.Diagnostics.CodeAnalysis attributes internally and annotate TryGet (audit ErrorDescription for [NotNullWhen(false)] spots the code already comments on).
Acceptance criteria
outcome.Then(() => receipt) and PrimaryPortError.Create(code, msg, domainError) compile and behave as expected, with tests; TryGet flows non-null on true for NRT consumers.
Context
Surfaced by the 2026-07-20 architecture, design & ecosystem audit (doc/handwritten/for-maintainers/audit/2026-07-20-firstclasserrors-architecture-and-design-audit.md, §9.3(b)(d)/§14-HV10; branch claude/firstclasserrors-audit-83gap7).
Problem
Three symmetry gaps force ceremony the ADRs elsewhere removed. (a) Non-generic
Outcomelacks the ADR-0003 value-mappingThen: producing a value after a void command requiresoutcome.Then(() => Outcome<X>.Success(v))— precisely the shape ADR-0003 eliminated onOutcome<T>. (b)PrimaryPortError/SecondaryPortErrorlack the single-inner-errorCreateoverload thatDomainErrorandInfrastructureErrorboth have — wrapping ONE domain error (the most common boundary case) requiresnew PrimaryPortInnerErrors().Add(error). (c)ErrorContext.TryGet<T>has no[NotNullWhen(true)], so NRT consumers must null-forgive after atruereturn; the standard netstandard2.0 mitigation (internally declared flow attributes) is applied nowhere.Impact
First-week friction in an API that has taught users to expect symmetry; all three are additive and cheap only until v1.
Direction
Outcome.Then<TResult>(Func<TResult>)(+ async twin), proven safe by the same overload-betterness argument as ADR-0003, with the lock-in proof added toOutcomeThenOverloadResolutionTests.PrimaryPortError.Create(code, msg, [transience,] DomainError innerError, …)and the SecondaryPortError twin.System.Diagnostics.CodeAnalysisattributes internally and annotateTryGet(auditErrorDescriptionfor[NotNullWhen(false)]spots the code already comments on).Acceptance criteria
outcome.Then(() => receipt)andPrimaryPortError.Create(code, msg, domainError)compile and behave as expected, with tests;TryGetflows non-null ontruefor NRT consumers.Context
Surfaced by the 2026-07-20 architecture, design & ecosystem audit (
doc/handwritten/for-maintainers/audit/2026-07-20-firstclasserrors-architecture-and-design-audit.md, §9.3(b)(d)/§14-HV10; branchclaude/firstclasserrors-audit-83gap7).