-
Notifications
You must be signed in to change notification settings - Fork 154
docs: Add deprecation policy #2148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,139 @@ | ||||||||||||
| # Deprecation policy | ||||||||||||
|
|
||||||||||||
| ## Preamble | ||||||||||||
|
|
||||||||||||
| The Content Authenticity Initiative SDKs are evolving projects. Prior to their 1.0 release, the APIs may change as we refine our design. That said, we are committed to making those changes in a transparent, predictable way so that developers can plan accordingly. | ||||||||||||
|
|
||||||||||||
| This policy applies to the Rust SDK and all language bindings (JavaScript, Node.js, C, C++, Swift, Kotlin, and Python). | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Prefer to refer to each repo as a "library" vs. the entire set as the "SDK". This is the terminology used in the docs. |
||||||||||||
|
|
||||||||||||
| ## Versioning and stability guarantees | ||||||||||||
|
|
||||||||||||
| We follow [Semantic Versioning (SemVer)](https://semver.org/). Version 1.0.0 will define the public API, and after that release, the way version numbers are incremented will be dependent on how the public API changes: patch for backward-compatible bug fixes, minor for backward-compatible additions, and major for incompatible changes. | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Small wording change so that the doc will not be time-specific: "1.0.0 will define..." implies the release is in future--which it is now, but won't be later. And formatting change to make it easier to read.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll partially accept this. IMHO we should retain the future-tense wording and change the language when we actually reach 1.0.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Just don't forget that part! |
||||||||||||
|
|
||||||||||||
| **Before 1.0:** Major version zero (`0.y.z`) is for initial development — anything may change at any time, and the public API should not be considered stable. In the Rust/Cargo ecosystem, this means that a change from `0.2.3` to `0.3.0` may include incompatible API changes. We will, however, make a good-faith effort to follow the deprecation process below even before 1.0, so that users have advance warning before breakage occurs. | ||||||||||||
|
|
||||||||||||
| **After 1.0:** Breaking changes will only ship in major version bumps. Before completely removing functionality in a new major release, there should be at least one minor release that contains the deprecation so that users can smoothly transition to the new API. We will publish and retain historical documentation for at least each minor point release. | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Small wording changes:
|
||||||||||||
|
|
||||||||||||
| ## What counts as a breaking change | ||||||||||||
|
|
||||||||||||
| Not all changes are equal. Breaking changes are assumed to be major changes, but not all breaking changes are major. The goal is that the same code should be able to run against different minor revisions, and minor changes should require at most a few local annotations. (This document is Rust-specific; we will treat other languages as closely to this list as is feasible.) | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is confusing. Do you mean "Breaking changes are assumed to be major changes, but not all major changes are breaking changes." ? If so, maybe reword as "All breaking changes are major changes, but not all major changes are breaking." If not, then what exactly does this mean? Most breaking changes are major, but in some cases they are not? When are breaking changes NOT major?? Please clarify. |
||||||||||||
|
|
||||||||||||
| Changes we consider **breaking** (requiring a major version bump post-1.0): | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
|
||||||||||||
| - Moving a public type, function, method, trait, or constant from one parent module to another | ||||||||||||
| - Removing or renaming a public type, function, method, trait, or constant | ||||||||||||
| - Changing the signature of a public function (parameter types, return types, or generics) except to the extent such changes are generally considered non-breaking (e.g. changing a `&mut Type` to `&Type`) | ||||||||||||
| - Changing the behavior of a public API in a way that violates previously documented contracts | ||||||||||||
| - Removing or renaming public enum variants or struct fields | ||||||||||||
| - Adding public enum variants or struct fields (unless `#[non_exhaustive]` was applied) | ||||||||||||
| - Breaking changes to upstream or third-party libraries to the extent that those APIs are re-published by our library and thus break our own API compatibility | ||||||||||||
| - Any other change flagged by `cargo-server-checks` (or an equivalent tool for any other language) as breaking compatibility | ||||||||||||
|
|
||||||||||||
| Changes we consider **non-breaking** (minor or patch): | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
|
||||||||||||
| - Adding new public items (types, functions, trait impls) | ||||||||||||
| - Deprecating a public item without removing it | ||||||||||||
| - Bug fixes that restore documented behavior | ||||||||||||
|
|
||||||||||||
| ## The deprecation process | ||||||||||||
|
|
||||||||||||
| When we decide to remove or replace part of the public API, we follow a three-stage process: | ||||||||||||
|
|
||||||||||||
| ### Stage 1: Deprecation notice (minor release) | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
|
||||||||||||
| - The item is marked deprecated in source code using the appropriate language mechanism. (See "Language-specific deprecation annotations" below.) | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a numbered list, because the steps are performed in the specified order. |
||||||||||||
| - The deprecation message includes: what is deprecated, why, what to use instead, and the earliest planned removal timeline. (See stage 2.) | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it is practical or necessary to add the earliest removal timeline. that's very subjective. Stage 2 already lets people know our general rules. I think this would just be misleading most of the time.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree. It's pretty easy to do the date math on the day we declare something deprecated. Having that date in the deprecation notice (and also as a substitute for your suggestion at line 74 above) will remind us to actually remove it when we can. |
||||||||||||
| - The change is documented in the CHANGELOG under a `### Deprecated` heading. | ||||||||||||
| - An announcement is posted in the project's Discord and, where applicable, linked from the relevant GitHub issue or PR. | ||||||||||||
|
|
||||||||||||
| ### Stage 2: Grace period | ||||||||||||
|
|
||||||||||||
| The grace period is a timeframe during which the deprecated API remains operational before being retired. Our minimums are: | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
|
||||||||||||
| | SDK maturity | Minimum grace period | | ||||||||||||
| | -- | -- | | ||||||||||||
| | Pre-1.0 | 60 days | | ||||||||||||
| | Post-1.0 | 90 days | | ||||||||||||
|
|
||||||||||||
| During the grace period, the deprecated API will continue to work without functional regression. **Exception:** We may remove deprecated APIs before this window expires if needed to address serious security issues or vulnerabilities. | ||||||||||||
|
|
||||||||||||
| ### Stage 3: Removal | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
|
||||||||||||
| - The deprecated item is removed in the next major release after the announced grace period has elapsed. **Exception:** A minor release may be used for these cases: | ||||||||||||
| - The item was marked as deprecated prior to the 1.0.0 release. | ||||||||||||
| - The item was only ever made public via a non-default feature/build configuration. | ||||||||||||
| - The migration guide (see "Migration guides", below) is updated to reflect the removal as permanent. | ||||||||||||
|
|
||||||||||||
| ## Language-specific deprecation annotations | ||||||||||||
|
|
||||||||||||
| Deprecation warnings will be expressed using each language's idiomatic mechanism so that developers are alerted by their compiler or toolchain. | ||||||||||||
|
|
||||||||||||
| ### Rust | ||||||||||||
|
|
||||||||||||
| ```rust | ||||||||||||
| #[deprecated(since = "0.5.0", note = "Use `Builder::new_v2()` instead. Will be removed in 0.7.0.")] | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no way we are going to know what version will remove the code. Versions are not fixed to a timeline. It's hard enough to estimate the version we deprecate given the way our builds go. |
||||||||||||
| pub fn old_builder() -> Builder { ... } | ||||||||||||
| ``` | ||||||||||||
|
|
||||||||||||
| ### Python | ||||||||||||
|
|
||||||||||||
| Use `warnings.warn()` with `DeprecationWarning`: | ||||||||||||
|
|
||||||||||||
| ```python | ||||||||||||
| import warnings | ||||||||||||
|
|
||||||||||||
| def old_function(): | ||||||||||||
| warnings.warn( | ||||||||||||
| "old_function() is deprecated since 0.5.0; use new_function() instead." " Will be removed in 0.7.0.", DeprecationWarning, stacklevel=2, | ||||||||||||
| ) | ||||||||||||
| ``` | ||||||||||||
|
|
||||||||||||
| The `@warnings.deprecated()` decorator can be used on a class, function, or method to mark it as deprecated. By default, it raises a runtime `DeprecationWarning` and also enables static type checkers to surface the deprecation at the call site. [Python](https://peps.python.org/pep-0702/) | ||||||||||||
|
|
||||||||||||
| ### JavaScript / Node.js | ||||||||||||
|
|
||||||||||||
| Use the `/** @deprecated */` JSDoc tag for IDE/toolchain visibility, and optionally emit a `console.warn` or Node.js `process.emitWarning` at runtime for dynamic detection. | ||||||||||||
|
|
||||||||||||
| ### C / C++ | ||||||||||||
|
|
||||||||||||
| ```C++ | ||||||||||||
| __attribute__((deprecated("message")))``[[deprecated("message")]] | ||||||||||||
| ``` | ||||||||||||
|
|
||||||||||||
| Also use `__declspec(deprecated)` to ensure deprecations are visible on Windows platforms. | ||||||||||||
|
|
||||||||||||
| ### Swift | ||||||||||||
|
|
||||||||||||
| Use `@available(*, deprecated, renamed: "newFunction", message: "Use newFunction() instead.")`. | ||||||||||||
|
|
||||||||||||
| ### Kotlin | ||||||||||||
|
|
||||||||||||
| Use `@Deprecated(message = "...", replaceWith = ReplaceWith("newFunction()"))`. | ||||||||||||
|
|
||||||||||||
| ## Migration guides | ||||||||||||
|
|
||||||||||||
| Every deprecation will be accompanied by a migration guide. We will provide alternatives or newer versions for deprecated features — if an item is scheduled for removal, users should know the recommended replacement. | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with the principal of letting people know that something is being removed and why. We should also let them know about alternatives. But the idea that every deprecation requires a before/after code comparison seems too much. Some should have this treatment, but not all. We have a LOT to deprecate. For some things no one ever knew about them and there were no previous code examples. |
||||||||||||
|
|
||||||||||||
| Migration guides should be published as: | ||||||||||||
|
|
||||||||||||
| - A section in the CHANGELOG entry for the deprecating release | ||||||||||||
| - A page or section in the SDK documentation site (linking from the deprecated symbol's doc comment) | ||||||||||||
| - A note in any relevant GitHub issue or discussion thread | ||||||||||||
|
|
||||||||||||
| Guides will include: the reason for the change, a before/after code comparison, any behavioral differences to be aware of, and the removal timeline. | ||||||||||||
|
|
||||||||||||
| ## Communication channels | ||||||||||||
|
|
||||||||||||
| Send announcements about deprecations through channels where the developer community is active — mailing lists, forums, and platforms like GitHub. Our standard channels are: | ||||||||||||
|
|
||||||||||||
| - **CHANGELOG.md:** required for every deprecation | ||||||||||||
| - **GitHub Release Notes:** summary of deprecations in each release. These are also reproduced in the doc site. | ||||||||||||
| - **Doc site:** deprecated symbols are visually flagged in all API references where the deprecated APIs are documented. | ||||||||||||
|
|
||||||||||||
| ## Security and bug-fix exceptions | ||||||||||||
|
|
||||||||||||
| If a deprecated API contains a security vulnerability, we reserve the right to either patch it in place or accelerate its removal, with as much notice as is practical given the severity. In such cases, we will coordinate with known downstream users and post a security advisory. | ||||||||||||
|
|
||||||||||||
| ## Feedback and exceptions | ||||||||||||
|
|
||||||||||||
| If the deprecation timeline creates a significant hardship for your project, please open a GitHub issue. We will consider extension requests, particularly for users with demonstrated adoption. Our goal is to evolve the SDK without leaving the community behind. | ||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No section heading is needed for this introductory section. "Preamble" is a bit grandiose for this document IMHO.