docs(api-reference): publish the API deprecation policy - #2832
aaronmichaelacosta wants to merge 6 commits into
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
abhijna
left a comment
There was a problem hiding this comment.
Hi! Thanks for writing this doc. Made some style and voice changes to sync with our technical docs guide. Please lmk if you have any questions
|
@aaronmichaelacosta I've asked @andy-r2c to take a first review from the PM side and asked him to let me know when it's ready for me to give a final look. I want to be sure we're aligned from both the Product and Eng side of things before we publish. Thank you for writing this up, also! |
Takes all twelve suggestions from the review on #2832 verbatim: the intro and summary sentences, the maturity table's header and all three rows, the undocumented-endpoints paragraph, the security and legal exception (now two paragraphs), the "Identify deprecated endpoints" heading, and the four-bullet list in its label-prefixed form. Two of the twelve needed a judgement call rather than a substitution: - One was a question -- "Do we add callouts in the API docs? If so, this info would benefit from being in a callout box." We do; <Note> appears 152 times in this repo. The summary paragraph is now a <Note>, using the suggested wording. - The frontmatter description suggestion was left on the v1 page, but v1 and v2 are deliberate duplicates importing the same snippet, so applying it to one only would have made them diverge. Both are updated. Style and voice only. Nothing here changes what the policy commits to, including the six-month window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Takes all twelve suggestions from the review on #2832: the intro and summary sentences, the maturity table's header and all three rows, the undocumented-endpoints paragraph, the security and legal exception (now two paragraphs), the "Identify deprecated endpoints" heading, and the four-bullet list in its label-prefixed form. Two of the twelve needed a judgement call rather than a substitution: - One was a question -- "Do we add callouts in the API docs? If so, this info would benefit from being in a callout box." We do; <Note> appears 152 times in this repo. The summary paragraph is now a <Note>, using the suggested wording. - The frontmatter description suggestion was left on the v1 page, but v1 and v2 are deliberate duplicates importing the same snippet, so applying it to one only would have made them diverge. Both are updated. The undocumented-endpoints suggestion carried a double space after its first period, which is dropped as a typo rather than reproduced. Style and voice only. Nothing here changes what the policy commits to, including the six-month window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
9400249 to
691f1ba
Compare
d413c13 to
e15c480
Compare
691f1ba to
547a2d0
Compare
connorg
left a comment
There was a problem hiding this comment.
I gave this a closer read after our review meeting.
The overall direction of my comments is the same, and I've tried to clearly note which would be blocking and which wouldn't.
I did become more concerned about the absolute-ness of the exception language and think we'd do better to soften it a touch.
| APIs change over time. This policy explains how much notice you'll receive before a breaking change affects your integration. | ||
|
|
||
| <Note> | ||
| In summary, **stable endpoints receive at least 6 months' notice before a breaking change or a removal.** After the deprecation period ends, the endpoint returns `410 Gone` with a machine-readable pointer to its replacement. It never returns incorrect or partial data. |
There was a problem hiding this comment.
Non-blocking:
the endpoint returns
410 Gonewith a machine-readable pointer to its replacement.
Once we know what the machine-readable response is going to be, we should document it on this page.
| This policy applies to every endpoint documented on [docs.semgrep.dev](https://docs.semgrep.dev/), according to its maturity level. | ||
|
|
||
| | Maturity | What to expect | Notice before a breaking change or removal | | ||
| | --- | --- | --- | | ||
| | **Stable** | Covered by the Semgrep API deprecation policy. | 6 months | | ||
| | **Beta** | Supported and documented. Semgrep maintains backward compatibility during the beta period, but the endpoint may still be renamed or removed. | 60 days | | ||
| | **Experimental** | Published to help you preview functionality. Experimental endpoints may change, be renamed, or be removed at any time without notice. | None | | ||
|
|
||
| Each endpoint's maturity is shown as a badge in the API reference and as a badge extension in the OpenAPI spec. |
There was a problem hiding this comment.
Non-blocking, style.
After reading the first sentence, I'm wondering "how do I know an endpoint's maturity level?". So moving that answer up could be helpful.
Not a strong opinion; the flow works as it stands.
| This policy applies to every endpoint documented on [docs.semgrep.dev](https://docs.semgrep.dev/), according to its maturity level. | |
| | Maturity | What to expect | Notice before a breaking change or removal | | |
| | --- | --- | --- | | |
| | **Stable** | Covered by the Semgrep API deprecation policy. | 6 months | | |
| | **Beta** | Supported and documented. Semgrep maintains backward compatibility during the beta period, but the endpoint may still be renamed or removed. | 60 days | | |
| | **Experimental** | Published to help you preview functionality. Experimental endpoints may change, be renamed, or be removed at any time without notice. | None | | |
| Each endpoint's maturity is shown as a badge in the API reference and as a badge extension in the OpenAPI spec. | |
| This policy applies to every endpoint documented on [docs.semgrep.dev](https://docs.semgrep.dev/), according to its maturity level. | |
| Each endpoint's maturity is shown as a badge in the API reference and as a badge extension in the OpenAPI spec. | |
| | Maturity | What to expect | Notice before a breaking change or removal | | |
| | --- | --- | --- | | |
| | **Stable** | Covered by the Semgrep API deprecation policy. | 6 months | | |
| | **Beta** | Supported and documented. Semgrep maintains backward compatibility during the beta period, but the endpoint may still be renamed or removed. | 60 days | | |
| | **Experimental** | Published to help you preview functionality. Experimental endpoints may change, be renamed, or be removed at any time without notice. | None | |
|
|
||
| ## Identify deprecated endpoints | ||
|
|
||
| - Subscribe to the API changelog: Every deprecation is announced in the changelog on the day it ships and is tagged as Deprecated. Each API version has its own RSS feed. Subscribe to the [v1](/api-reference/v1/Changelog) or [v2](/api-reference/v2/Changelog) feed to receive deprecation notices automatically. |
There was a problem hiding this comment.
Non-blocking question.
I see you're adding these pages in #2796.
One question about that approach: if you're auto-generating the changelog, won't you need a different way to publish the advance notice 60–180 days before the change?
|
|
||
| | Maturity | What to expect | Notice before a breaking change or removal | | ||
| | --- | --- | --- | | ||
| | **Stable** | Covered by the Semgrep API deprecation policy. | 6 months | |
There was a problem hiding this comment.
Suggestion (non-blocking)
I just thought about this and realized it might be more predictable to have a literal number of days vs relying on variable-length months
| | **Stable** | Covered by the Semgrep API deprecation policy. | 6 months | | |
| | **Stable** | Covered by the Semgrep API deprecation policy. | 180 days | |
If changed, also change in the text above
|
|
||
| | Maturity | What to expect | Notice before a breaking change or removal | | ||
| | --- | --- | --- | | ||
| | **Stable** | Covered by the Semgrep API deprecation policy. | 6 months | |
There was a problem hiding this comment.
Not strictly blocking, but recommend fixing
Just realized on a closer reading that the existing wording doesn't really add value ("stable = covered by this policy"). But all APIs are covered by this policy, including Beta. Maybe something like:
| | **Stable** | Covered by the Semgrep API deprecation policy. | 6 months | | |
| | **Stable** | Supported and documented. Expected to evolve and improve without breaking changes. | 6 months | |
| ### The one exception: urgent security and legal changes | ||
|
|
||
| If continuing to support an endpoint or field would expose customer data, create a security risk, or violate a legal obligation, Semgrep may make changes with less notice than described above, or in rare cases, without notice. | ||
|
|
||
| This is the only exception to the deprecation policy. Semgrep does not invoke it for convenience. When invoked, Semgrep will communicate what changed and why as soon as possible. |
There was a problem hiding this comment.
Reframe (blocking)
I want to be careful about making exclusive claims like "the one exception". I would rather
- still make it clear this is to be done carefully
- but not claim this is literally the only reason we might do it
- also not mention "legal" as this sort of opens up a can of worms IMO
| ### The one exception: urgent security and legal changes | |
| If continuing to support an endpoint or field would expose customer data, create a security risk, or violate a legal obligation, Semgrep may make changes with less notice than described above, or in rare cases, without notice. | |
| This is the only exception to the deprecation policy. Semgrep does not invoke it for convenience. When invoked, Semgrep will communicate what changed and why as soon as possible. | |
| ### Exception: unavoidable urgent changes | |
| If continuing to support an endpoint, field, or other aspect of API behavior would expose customer data, create a security risk, or violate an obligation, Semgrep may make changes with less notice than described above, or in rare cases without notice. | |
| Semgrep will not invoke this exception lightly. When invoked, Semgrep will communicate what changed and why as soon as possible. |
|
|
||
| This policy applies to every endpoint documented on [docs.semgrep.dev](https://docs.semgrep.dev/), according to its maturity level. | ||
|
|
||
| | Maturity | What to expect | Notice before a breaking change or removal | |
There was a problem hiding this comment.
Comment (non-blocking)
I know you removed the details of what we consider a breaking change. However, I think as a reader I'd like to know what we consider in scope and out of scope. For example, I would want to know that Semgrep won't change URL paths or remove fields I might rely on.
Notably we could frame this either as "what would a break be" (negative) or "what do we promise stays the same" (positive).
63ffe35 to
9046272
Compare
f13765c to
37ee39b
Compare
Adds a Deprecation Policy page alongside the changelog in both API versions, from the customer-facing half of the APPEX-956 policy doc. The internal appendix (notice channels, the 410-vs-301 decision record, open gaps) is not published. The body lives in a snippet imported by both version pages. Terms-of-Use duplicates its one sentence per version, but 30 lines of policy would drift, and the repo already shares longer content this way (see snippets/metrics.mdx). One content change from the source doc: it was written before we decided to publish a changelog, so "Finding out what is deprecated today" had no push channel -- only the reference, response headers, and support. It now leads with the changelog and its RSS feed, which records every deprecation tagged Deprecated on the day it ships. Deliberately not carried over: the in-app banner and admin email named in the internal appendix. Neither exists yet (appendix gap 4), so publishing them would commit us to channels we cannot serve. The invented /api/migrations/<resource> URL (gap 5) appears only in the appendix and is not published either. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Stable endpoints had two clocks: 6 months for a breaking change, 3 months for removing an already-deprecated optional field. The short one does not survive contact with how the clock actually starts. Per styleguide 13.2 the clock only runs once the notice is public -- `Deprecation` and `Sunset` headers live, spec marked. A field marked deprecated with no sunset date has therefore started no clock at all, so the 3 months would be the entire notice a customer gets, not a follow-on to time already served. That is half the window for something oasdiff rates `response-optional-property-removed` at WARN, potentially breaking: "optional" says the server may omit the field, not that nobody reads it. One window for stable, whatever the change. Simpler to state, simpler to honour, and it errs long on a public commitment. Styleguide 13.1 transcribes this table and still carries the 3-month row; that needs the same edit in semgrep-app. Its link to api-deprecation-policy.md is also dangling -- that file does not exist in that repo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Takes all twelve suggestions from the review on #2832: the intro and summary sentences, the maturity table's header and all three rows, the undocumented-endpoints paragraph, the security and legal exception (now two paragraphs), the "Identify deprecated endpoints" heading, and the four-bullet list in its label-prefixed form. Two of the twelve needed a judgement call rather than a substitution: - One was a question -- "Do we add callouts in the API docs? If so, this info would benefit from being in a callout box." We do; <Note> appears 152 times in this repo. The summary paragraph is now a <Note>, using the suggested wording. - The frontmatter description suggestion was left on the v1 page, but v1 and v2 are deliberate duplicates importing the same snippet, so applying it to one only would have made them diverge. Both are updated. The undocumented-endpoints suggestion carried a double space after its first period, which is dropped as a typo rather than reproduced. Style and voice only. Nothing here changes what the policy commits to, including the six-month window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Doubles the beta notice period from 30 days to 60. 30 days is a short window for a customer to notice a deprecation, schedule the work, and ship it -- particularly for teams on a monthly release train, where it can amount to a single opportunity to react. Stable stays at 6 months and experimental still promises nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Connor's review, plus two accuracy fixes the 410 write-up turned up.
Reviewer-requested:
- Move the maturity-badge sentence above the table, so the question the
table raises ("how do I know which one an endpoint is?") is answered
before it is asked rather than after.
- State stable's window as 180 days. Beta was already in days, so the
column no longer mixes units, and a month-length assumption cannot
change what the commitment means.
- Rewrite the stable row, which said only "covered by this policy". Beta
is covered too, so the cell distinguished nothing.
- Soften the exception. It claimed to be "the only exception" and named
a legal obligation specifically; both are more absolute than we can
actually promise. Same care, less cornering.
- Restore what counts as a breaking change, from the APPEX-956 draft.
Split into what will not change without notice and what may change at
any time, because the second half is what a caller has to build for --
tolerate new fields, do not match on error strings.
APPEX-956 wanted that definition to be a link to the oasdiff ruleset in
APPEX-959, so it would be mechanical rather than prose. APPEX-959 is
cancelled, so prose is what is left.
Accuracy, found while writing the sunset section against the
implementation in semgrep-app#31680:
- The `Link` header is the machine-readable pointer, and it is omitted
when a removal has no replacement. "Returns 410 with a machine-readable
pointer to its replacement" promised it unconditionally.
- Document the sunset response itself: headers, body, and which parts are
stable enough to parse. `error` wording is not.
semgrep-app#31680 is still a draft, so this must not publish before it
ships -- the page would describe a response nothing returns yet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two claims on this page were ahead of the generator, and both are now true rather than aspirational. "Tagged as Deprecated" described a chip in the Change column as though it were a filter. The filter tag was "Non-breaking", so a reader who followed this page's advice -- subscribe, watch for what will break you -- was told to filter for exactly the thing that hid the notice. The generator now files deprecations as potentially breaking, so say both: what the row is marked, and which filter it survives. Also say that the removal itself lands in the changelog. It did not previously; a removal that served its full notice window produced no entry at all, which made "the changelog records every deprecation" true and "the changelog tells you when the endpoint went away" false. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
37ee39b to
adb9a7d
Compare
9046272 to
670a374
Compare

What this adds
A Deprecation Policy page for the public API, sitting next to the changelog in both versions:
/api-reference/v1/Deprecation-Policy/api-reference/v2/Deprecation-PolicyIt answers one customer question: how much warning do I get before a Semgrep API change breaks my integration? Short version — stable endpoints get 6 months' notice for a breaking change, beta gets 30 days, experimental gets none, and undocumented endpoints aren't covered at all. At the deadline the endpoint returns
410 Gonerather than quietly serving wrong data.The text is the customer-facing half of the policy drafted in APPEX-956. The internal appendix — notice channels, the 410-vs-301 decision record, known gaps — is not published.
One change from the draft
The policy was written before we decided to ship a changelog, so its "how do I find out what's deprecated" list had no way for a customer to be told proactively — only the reference, response headers, and emailing support. It now leads with the changelog and its RSS feed, which records every deprecation on the day it ships.
Notes for review
Test plan
npx mintlify@latest validatepassesStacked on #2796 — this page links to the changelog pages that PR adds, so it should merge after it.