feat(spec,gates): serve error responses as RFC 9457 problem details - #104
Open
ucekmez wants to merge 1 commit into
Open
feat(spec,gates): serve error responses as RFC 9457 problem details#104ucekmez wants to merge 1 commit into
ucekmez wants to merge 1 commit into
Conversation
9 tasks
ucekmez
force-pushed
the
fix/devendor-conformance-criteria
branch
from
August 26, 2026 19:39
26d91a7 to
8d392ab
Compare
`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
force-pushed
the
feat/rfc9457-problem-details
branch
from
August 26, 2026 19:39
4245e37 to
11bd504
Compare
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.
Summary
PR 12 of a stacked series. Base is #103. Not for merge without review.
EEP defines four bespoke error envelopes —
gate.402/403/429/451-response.json— each with its ownerrorstring convention, understood by nothing outside EEP.application/problem+jsonis 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
typeMUST NOT vary to encode per-occurrence information (that is whatdetailis for), and clients MUST tolerate unknown extension members.type/title/status/detail/instance, withtypeandstatusconstrained per response so a 402 document cannot claim to be a 429.@eep-dev/gatespopulates the members inbuild402Response/build429Response, exports the problem type URIs and the media type, and setsContent-Typeon 429 headers.@eep-dev/middlewaresetsContent-Type: application/problem+jsonon 402 responses — RFC 9457 requires the media type, not just the body shape.typehttps://eep.dev/problems/payment-requiredhttps://eep.dev/problems/access-restrictedhttps://eep.dev/problems/rate-limitedhttps://eep.dev/problems/legally-restrictedScope
Checklist
@eep-dev/gatesbuilders now emit them, which is a visible output change worth a CHANGELOG line.Verification
@eep-dev/gates@eep-dev/middlewaretests/compliance-cli --fixturestests/cross-impl/test_conformance_fixtures.pycodegen-schema-types --checkNotes for reviewers
Two tests exist specifically to pin the RFC's semantics, not just its field names:
titlestays stable across different resources whiledetailvaries — RFC 9457 §3.1.1 makestitlea property of the type, and it is a common mistake to interpolate per-request data into it.Not done here, flagged rather than skipped:
eep-gatesbuilders are unchanged, so TS and Python now differ in output. Worth a parity follow-up.@eep-dev/gatesto populate — those responses are constructed by implementers today.errorin place rather than deprecating it. Removing it would be the breaking half of this change and belongs in a v0.2 discussion, not here.