Skip to content

Core: ship an Error→ProblemDetails projection and a FirstClassErrors.AspNetCore adapter #232

Description

@Reefact

Problem

The core model was designed for RFC 9457 — ShortMessage is documented as the problem title, DetailedMessage as detail (Error.cs XML docs), and the generated catalog mints urn:problem:{service}:{code} problem types (--service-name is mandatory precisely to render them). Yet no runtime code maps an Error to a ProblemDetails shape anywhere; the URN builder (ProblemType.cs) lives only in the net8.0 GenDoc tooling, unreachable from a deployed netstandard2.0 app. Every adopter hand-writes the one mapping where Design Principle 3 (public/internal separation) can be silently violated, and the catalog's documented HTTP examples can drift freely from actual API responses — the exact drift the thesis exists to eliminate, relocated to the HTTP boundary. The comparison page concedes this axis to ErrorOr.

Impact

The single highest-leverage competitive gap; the first thing API-team evaluators bounce off.

Direction

  • Core (dependency-free, netstandard2.0): error.ToProblemDetails(options) returning a neutral model — title = ShortMessage, detail = DetailedMessage (explicit opt-in), extensions code/instanceId/occurredAt, type composed by the same URN builder as the catalog (extract ProblemType from GenDoc into the core or a shared source file so runtime and catalog provably agree). DiagnosticMessage unreachable by construction.
  • Satellite FirstClassErrors.AspNetCore (net8.0+, following the RequestBinder/Testing/Dummies packaging precedent): Outcome<T>IResult/IActionResult terminals, an IExceptionHandler for DiagnosableException, a taxonomy-driven default status policy (DomainError/PrimaryPortError → 4xx; SecondaryPortError by Transience → 502/503/500) with per-code overrides, and services.AddFirstClassErrors(serviceName, …) bridging RequestBinderOptions.Default at composition time.
  • Fold in the binder host helpers the code already anticipates (ArgumentSourceExtensions.cs:7-9): a System.Text.Json-naming-policy-aware IArgumentNameProvider and HttpRequest extraction helpers.

Acceptance criteria

  • A consumer can return a catalog-consistent RFC 9457 response from an Outcome failure in one call, without touching DiagnosticMessage.
  • The problem type URN is byte-identical between runtime responses and the generated catalog for the same code.
  • The core package gains no runtime dependency.

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, §13.2/§14-C5; branch claude/firstclasserrors-audit-83gap7).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions