Skip to content

feat(spec,gates): serve error responses as RFC 9457 problem details - #104

Open
ucekmez wants to merge 1 commit into
fix/devendor-conformance-criteriafrom
feat/rfc9457-problem-details
Open

feat(spec,gates): serve error responses as RFC 9457 problem details#104
ucekmez wants to merge 1 commit into
fix/devendor-conformance-criteriafrom
feat/rfc9457-problem-details

Conversation

@ucekmez

@ucekmez ucekmez commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

PR 12 of a stacked series. Base is #103. Not for merge without review.

$ grep -ric 'rfc.?9457|rfc.?7807|application/problem' .
0

EEP defines four bespoke error envelopes — gate.402/403/429/451-response.json — each with its own error string convention, understood by nothing outside EEP.

application/problem+json is understood by generic HTTP clients, API gateways and agent frameworks without EEP-specific parsing, and it is what a standards reviewer expects to find. A bespoke error dialect was a cost EEP was paying for no benefit.

This is purely additive

Everything EEP already defined — unmet_requirements, required_tier, retry_after_seconds, signed_challenge, available_tiers — stays exactly as it was, now as RFC 9457 extension members.

{
  "type":   "https://eep.dev/problems/payment-required",  // ← new
  "title":  "Payment Required",                            // ← new
  "status": 402,                                           // ← new
  "detail": "Access to 'content.papers.full_text' requires the 'premium' tier.",
  "error": "access_restricted",        // ← unchanged
  "resource": "content.papers.full_text",
  "current_tier": "public",
  "required_tier": "premium",
  "unmet_requirements": [ /**/ ]
}

A client reading the existing fields keeps working. A client that speaks problem details gains a shape it already knows.

What changed

  • New normative §3.3.1 — required members, the four registered EEP problem type URIs, and two rules that matter in practice: type MUST NOT vary to encode per-occurrence information (that is what detail is for), and clients MUST tolerate unknown extension members.
  • All four gate schemas gain type/title/status/detail/instance, with type and status constrained per response so a 402 document cannot claim to be a 429.
  • @eep-dev/gates populates the members in build402Response/build429Response, exports the problem type URIs and the media type, and sets Content-Type on 429 headers.
  • @eep-dev/middleware sets Content-Type: application/problem+json on 402 responses — RFC 9457 requires the media type, not just the body shape.
Status type
402 https://eep.dev/problems/payment-required
403 https://eep.dev/problems/access-restricted
429 https://eep.dev/problems/rate-limited
451 https://eep.dev/problems/legally-restricted

Scope

  • Spec / schema only
  • TypeScript package(s)
  • Python package(s)
  • Tests / CI
  • Docs / examples

Checklist

  • I read CONTRIBUTING.md and CODE_OF_CONDUCT.md.
  • Tests added or updated where appropriate.
  • Breaking change? No fields removed or renamed; the new members are optional in the schemas, so existing responses still validate. @eep-dev/gates builders now emit them, which is a visible output change worth a CHANGELOG line.
  • Documentation updated for user-visible behavior.

Verification

Suite Result
@eep-dev/gates 486 passed (was 478)
@eep-dev/middleware 186 passed
tests/ 187 passed
compliance-cli --fixtures 23 vectors, 0 failed
tests/cross-impl/test_conformance_fixtures.py 25 passed
codegen-schema-types --check no drift

Notes for reviewers

Two tests exist specifically to pin the RFC's semantics, not just its field names:

  • title stays stable across different resources while detail varies — RFC 9457 §3.1.1 makes title a property of the type, and it is a common mistake to interpolate per-request data into it.
  • No pre-existing EEP field was dropped, asserted field by field.

Not done here, flagged rather than skipped:

  • The Python eep-gates builders are unchanged, so TS and Python now differ in output. Worth a parity follow-up.
  • 403 and 451 have schema members but no builder in @eep-dev/gates to populate — those responses are constructed by implementers today.
  • I left error in place rather than deprecating it. Removing it would be the breaking half of this change and belongs in a v0.2 discussion, not here.

Copilot AI lite review requested due to automatic review settings August 26, 2026 19:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

`grep -ri 'rfc.?9457|rfc.?7807|application/problem'` across the repo
returned zero matches. EEP defined four bespoke error envelopes —
`gate.402/403/429/451-response.json` — each with its own `error` string
convention, understood by nothing outside EEP.

`application/problem+json` is understood by generic HTTP clients, API
gateways and agent frameworks without EEP-specific parsing, and it is
what a standards reviewer expects to find. A bespoke error dialect is a
cost EEP was paying for no benefit.

This is purely additive. Everything EEP already defined —
`unmet_requirements`, `required_tier`, `retry_after_seconds`,
`signed_challenge` and the rest — stays exactly as it was, now as RFC
9457 *extension members*. A client reading the existing fields keeps
working; a client that speaks problem details gains a shape it already
knows.

Changes:
- New normative §3.3.1 defining the required members, the four
  registered EEP problem type URIs, and two rules that matter in
  practice: `type` MUST NOT vary to encode per-occurrence information
  (that is what `detail` is for), and clients MUST tolerate unknown
  extension members.
- `type`, `title`, `status`, `detail`, `instance` added to all four gate
  response schemas, with `type` and `status` constrained per response so
  a 402 document cannot claim to be a 429. Types regenerated.
- `@eep-dev/gates` populates the members in `build402Response` and
  `build429Response`, exports the problem type URIs and the
  `application/problem+json` media type, and sets it on the 429 headers.
- `@eep-dev/middleware` sets `Content-Type: application/problem+json` on
  its 402 responses — RFC 9457 requires the media type, not just the
  body shape.
- Tests pinning that `title` stays stable across occurrences while
  `detail` varies, and that no pre-existing field was dropped.

Refs: EEP audit 2026-08 finding B7
Signed-off-by: Ugur Cekmez <ucekmez@gmail.com>
@ucekmez
ucekmez force-pushed the feat/rfc9457-problem-details branch from 4245e37 to 11bd504 Compare August 26, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants