Repository navigation
Conversation
Restructures the Lifecycle Object around the operation-scoped deprecation/sunset model from discussion #5's April 2026+ comments (the root-level, document-wide draft from earlier in the thread is superseded) and places it under `features` on the Operation Object, consistent with the Standardized API Feature (SAF) concept being defined in OAI/OpenAPI-Specification#5310 and #5350. Fills in the Introduction, Relationship to the OpenAPI Specification, Definitions (Lifecycle Object, Sunset Object), a new informative Header Mapping section (field -> Deprecation/Sunset/Link header mapping per RFC 9745, RFC 8594, RFC 8288), Appendix A revision history, and a new informative Appendix B on AI agent/MCP tooling usage. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAmP3nFaRwCARS7JygrV7r
Align lifecycle.md with SAF framing, using discussion #5 example data
minor changes
…ample - Declare the SAF via the root `features` map (OAS PR #5447) and place the Lifecycle Object in a dedicated Operation Object `lifecycle` field - Add a complete OAS 3.3 example using `externalLinks` from the Docs Links proposal alongside the Lifecycle Object - Fix stale listPets_v2 reference in Appendix B Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Align lifecycle SAF with OAS #5447 features and add external links example
Swap `migration`, `replacement`, and `sunset.policy` for a single `lifecycle.externalLinks` array of External Documentation Objects, per the OAS Docs Links proposal. `kind` is required and uses IANA link relation names (`deprecation`, `successor-version`, `sunset`), so each link maps directly to a `Link` header; other kinds are documentation only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace named lifecycle link fields with an externalLinks array
The schema was a stub (`properties: {}` with `additionalProperties: false`)
that rejected every non-empty Lifecycle Object. It now validates the
Lifecycle, Sunset, and External Documentation Objects, requiring `kind` on
each `lifecycle.externalLinks` entry and rejecting the removed `migration`,
`replacement`, and `sunset.policy` fields.
Removes the unused Schema Object `$dynamicAnchor` hook and the matching
spec text, since the Lifecycle Object contains no Schema Objects.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Define the Lifecycle Object schema and add pass/fail tests
Define `deprecated` as the authoritative deprecation signal. Operations with `lifecycle` SHOULD set `deprecated: true`; if `deprecated` is absent or false, tools MUST treat the operation as not deprecated and MUST NOT generate headers or present it as deprecated from the Lifecycle Object. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Make deprecated take precedence over the Lifecycle Object
For consistency with the OAS schema, allow URI references, which are resolved against the document's base URI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@karenetheridge thanks for the review — I switched |
spec.openapis.org/oas/v3.3.0.html is not published yet, so the link check fails. Link the SAF section to the v3.3-dev source and the Operation and External Documentation Objects to the latest published OAS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
pinning this here for review: OAI/OpenAPI-Specification#5585 |
| sunset: | ||
| date: "2025-07-01T00:00:00Z" | ||
| externalLinks: | ||
| - kind: deprecation |
There was a problem hiding this comment.
it'd be beneficial to also have examples of how those values map to the response headers.
There was a problem hiding this comment.
Added in 0371a89: the complete example now shows the Deprecation, Sunset, and Link headers a server would emit for GET /v1/flights, with a table mapping each header to the Lifecycle Object field it comes from. It also notes that the changelog/announcement entries and the Operation Object's own externalLinks generate no headers.
| operationId: listFlights_v1 | ||
| summary: List all flights | ||
| deprecated: true | ||
| lifecycle: |
There was a problem hiding this comment.
this should probably go under a sub-field named "features" (or something like this) to avoid mutating the schema for the core objects.
so essentially
get:
features:
# this is a reserved field name/key for lifecycle
lifecycle:...Security would be the only one diverging from this for compat reason.
There was a problem hiding this comment.
We need a PR adding the container field to the OpenAPI Object, Path Item Object, and Operation Object (and maybe Response Object? I'm less sure of that so it can be added later). I think it would be great if someone other than me took a shot at this, but if no one is available I will do it.
There was a problem hiding this comment.
|
another thing that came up during the meeting is that we should get generic tooling vendors and get their opinions on the current shape of the spec, especially for scenarios where the lifecycle information and what shows up at runtime disagree. |
…ement Add the Deprecation, Sunset, and Link headers a server would emit for the complete example, with the Lifecycle Object field each comes from. Add an editor's note that the Lifecycle Object will move under the SAF container field once the OAS defines it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @baywet, agreed: vendor input on the current shape would be valuable before this settles. To make it concrete, here are the disagreement scenarios I'd suggest putting to them:
For context, the spec currently treats the OAD as the design-time source and the headers as an optional runtime byproduct (see Header Mapping and Relationship to Happy to collect the feedback in a discussion on this repo if that's useful. Are there specific vendors you'd suggest reaching out to? |
handrews
left a comment
There was a problem hiding this comment.
I haven't gotten through all of this (and I am wondering if we could perhaps break this up to make it easier to resolve pieces and make progress?) but I wanted to publish this before tomorrow's call. My feedback is on details, the direction is good.
| **Scope.** The Lifecycle Object applies at the Operation Object level only. An | ||
| earlier draft explored a root-level, document-wide object (see | ||
| [Appendix A](#appendix-a--revision-history)), but SIG discussion concluded | ||
| that a single OpenAPI document does not necessarily describe exactly one API, | ||
| so a document-wide deprecation signal does not generalize; see | ||
| [sig-lifecycle discussion #5](https://github.com/OAI/sig-lifecycle/discussions/5). | ||
| Applying the same lifecycle metadata uniformly across many operations remains | ||
| the job of [Overlays](https://spec.openapis.org/overlay/latest.html), not of | ||
| this object. |
There was a problem hiding this comment.
I think based on this we need to be explicit that trying to configure a lifecycle object at the other levels is an error. Otherwise it falls into the ambiguous area where things are maybe tolerated but ignored, which is not intuitive.
We do not need to include the history of the decision in the specification. Most readers wont' know what a "SIG discussion" is. I would just document the restriction and the Overlays approach for broader usage.
However, did we consider allowing it at the Path Item Object level? I'm not that familiar with how this will be used, but I have a vague sense that it's common to deprecate/sunset an entire endpoint, which would best be done at a Path Item level. There is also the question of deprecating only specific responses, but I feel like that's a "wait and see if anyone asks for it" thing.
| **Non-goal.** This SAF does not replace `deprecated: true`, which | ||
| remains the coarse signal tooling already recognizes (for example, to gray out | ||
| an operation in Swagger UI). The Lifecycle Object is additional detail used | ||
| alongside it. |
There was a problem hiding this comment.
In my view, framing like "Non-goal" is more of a proposal sort of thing. Since this is addressed in detail where usage is described, I would just leave it there. Mentioning it in the introduction without context or crosslink is a bit confusing.
| the OAS 3.2-compatible security behavior. As required by the OAS, all | ||
| documents in a multi-document OpenAPI Description MUST declare the same SAFs. |
There was a problem hiding this comment.
I'd link to the relevant section here and say something like "see OAS section 1.2.3.4 for guidance on using SAFs across multiple OpenAPI Description documents" so that there's no chance of this paragraph drifting from the main section.
| meant to complement — not replace — `deprecated: true` on the same Operation | ||
| Object. |
There was a problem hiding this comment.
I find "complement — not replace" to be a bit vague, but fortunately you have the more precise info available. Based on other text, the Lifecycle Object expands on the meaning of deprecated: true since that is required to be set in order for a Lifecycle Object to be usable.
| **Editor's note.** The placement of the Lifecycle Object is provisional. | ||
| SAFs are expected to place their objects under a container field that the OAS | ||
| will define on the OpenAPI, Path Item, and Operation Objects, so that SAFs | ||
| do not add fields directly to core objects. Once the OAS defines that | ||
| container, the Lifecycle Object will move under it, and the `lifecycle` field | ||
| described in [Operation Object Fields](#operation-object-fields) will be | ||
| replaced. |
There was a problem hiding this comment.
Let's go ahead and figure this out. Although it is reminding me that the reason I didn't use features for the declarations is that I wanted to use it for the fields... hmmm...
| including its `summary` and `kind` fields. This specification therefore | ||
| requires an OpenAPI Specification version that defines those fields. |
There was a problem hiding this comment.
Since these are going into 3.3 and there's no real expectation SAFs would work with an earlier version, I think we can cut this. Otherwise it kind-of implies that there are other versions that work with SAFs but not with this which is a bit confusing.
| The Operation Object's `deprecated` field is the authoritative signal of | ||
| whether an operation is deprecated, and takes precedence over the Lifecycle | ||
| Object. The Lifecycle Object only adds detail to an operation that | ||
| `deprecated` already marks as deprecated. | ||
|
|
||
| An Operation Object with a `lifecycle` field SHOULD set `deprecated: true`. | ||
|
|
||
| If `deprecated` is absent or `false`, tools MUST treat the operation as not | ||
| deprecated, even if a `lifecycle` field is present. In that case, tools: |
There was a problem hiding this comment.
I see what you're doing here in following how a lot of things in the OAS work. But a lot of those things would not be done the same way now. And many of them are like they are because we had to preserve compatibility. I would recommend:
- A Lifecycle Object MUST result in an error if
deprecated: trueis not set. (however, if you know of a use case where this would be a problem, that would be a good reason to make this only a SHOULD).
Silently ignoring something is bad UX, and I've seen real production problems from the parts of the OAS that do that.
| This specification defines the following `kind` values for entries in | ||
| `lifecycle.externalLinks`. Each value is the name of an IANA-registered link | ||
| relation, so a link's `kind` is also the `rel` of the `Link` header it maps to. | ||
|
|
There was a problem hiding this comment.
Does this mean that it's an error to use these relation types in a Link header description on headers fields on a Response Objects associated with operations with a Lifecycle Object? What if the Lifecycle SAF is enabled but there isn't a Lifecycle Object? (I would lean towards them always being an error if lifecycle is enabled- clear errors over ambiguous multiple options).
Summary
This PR brings the Lifecycle Specification in line with the SAF mechanism merged in OAI/OpenAPI-Specification#5447. It builds the Lifecycle Object on the Docs Links proposal, and replaces the stub schema with a real one. It supersedes #15.
SAF framing (operation-scoped, per discussion #5)
Deprecation(RFC 9745),Sunset(RFC 8594), andLinkheaders, and an informative appendix on AI agent / MCP use.Alignment with OAS #5447
featuresmap (features: { security: 1.0.0, lifecycle: 1.0.0 }). The spec notes thatsecuritymust be listed explicitly oncefeaturesis set.lifecyclefield, not in an operation-levelfeatures. This avoids reusing the rootfeaturesname with a different type.Adopting
externalLinks(Docs Links proposal)migration,replacement, andsunset.policyare replaced by a singlelifecycle.externalLinksarray of External Documentation Objects.kindis required on each entry.deprecation,successor-version, andsunsetare IANA link relation names, so each link maps directly toLink: <url>; rel="<kind>". Other kinds (for examplechangelog) are documentation only.lifecycle.externalLinks; general docs stay in the operation's ownexternalLinks.deprecatedtakes precedencedeprecatedis the authoritative signal. An operation withlifecycleSHOULD setdeprecated: true. Ifdeprecatedis absent orfalse, tools MUST treat the operation as not deprecated and ignorelifecycle: no headers, no deprecation annotations.deprecated: truewithoutlifecycleworks as before, so APIs can adopt the SAF gradually.Schema
properties: {}+additionalProperties: false) rejected every non-empty Lifecycle Object. The new schema validates the Lifecycle, Sunset, and External Documentation Objects, and requireskindinlifecycle.externalLinks.Open questions for the SIG
lifecyclethe right name for the Operation Object field?lifecycle: 1.1.0.sunset.date>=date; the compatibility[TODO]is unfilled.Test plan
oai-spec-test tests/schema— 24 passed, 100% schema coverageyarn validate-markdown(not run locally)