diff --git a/README.md b/README.md index 007802e..8bab6c1 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,33 @@ The desktop app uses [pywebview](https://pywebview.flowrl.com/) to render the Fl - **Frontend:** Vanilla HTML/CSS/JS (no npm, no build step) - **PDF:** fpdf2 +## Versioning + +> **Merge note:** The full policy and `CHANGELOG.md` ship in [PR #85](https://github.com/cppalliance/cppa-cursor-browser/pull/85) (#74). Land that PR with or before this one to avoid duplicate or dead links. + +This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) (`MAJOR.MINOR.PATCH`). + +**Pre-1.0 stability (current):** The project is at `0.x.y`. During this phase: + +- **Minor version bumps (`0.x` → `0.x+1`)** may include breaking changes to the HTTP API, CLI flags, or exported file formats. Consumers of the `/api/*` endpoints or the `cursor-chat-export` CLI should review the changelog before upgrading. +- **Patch version bumps (`0.x.y` → `0.x.y+1`)** are backward-compatible bug fixes only. Critical security fixes may break compatibility at any version with appropriate changelog notation. + +**What constitutes a breaking change:** + +| Surface | Breaking examples | +|---|---| +| HTTP API | Removing or renaming an endpoint; changing the JSON schema of a response in a non-additive way | +| CLI (`cursor-chat-export`) | Removing or renaming a flag; changing default output structure | +| Export formats | Removing YAML frontmatter fields; changing the zip directory layout | + +Internal Python modules are not a semver-governed library API for external importers. + +Adding new optional fields to JSON responses, adding new CLI flags with sensible defaults, or adding new export-format sections are *not* considered breaking. + +Notable changes will be documented in **[CHANGELOG.md](CHANGELOG.md)** following the [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format (see #74 / PR #85). + +When an API surface is scheduled for removal, follow the process in **[docs/API_DEPRECATION.md](docs/API_DEPRECATION.md)** (response headers, changelog entries, minimum notice period). + ## License This project is licensed under the [Boost Software License 1.0](https://www.boost.org/LICENSE_1_0.txt). diff --git a/docs/API_DEPRECATION.md b/docs/API_DEPRECATION.md new file mode 100644 index 0000000..b0af559 --- /dev/null +++ b/docs/API_DEPRECATION.md @@ -0,0 +1,53 @@ +# API Deprecation Policy + +How the HTTP API (`/api/*`), CLI flags (`cursor-chat-export`), and shared JSON response fields are deprecated and removed. Complements the [Versioning](../README.md#versioning) section and [CHANGELOG.md](../CHANGELOG.md). + +## Pre-1.0 posture + +While the project is at `0.x.y`, **breaking changes may land in any minor release** without a prior deprecation cycle. Deprecations are still recorded in the changelog when practicable, but there is no guarantee of advance notice before removal. Pre-1.0, workflow steps 2–4 (CLI help text, response headers, server logs) are **encouraged but optional**; step 1 (changelog) applies when practicable. After `1.0.0`, the workflow below applies in full. + +## Deprecation workflow + +When an endpoint, parameter, response field, or CLI flag is scheduled for removal: + +1. **CHANGELOG** — Add an entry under `### Deprecated` naming the surface, its replacement (if any), and the planned removal version. +2. **CLI help** (flags only) — Add `(deprecated, use )` to the flag's argparse help string. +3. **Response headers** — Deprecated HTTP endpoints and parameters emit deprecation headers on every affected response (see [Header format](#header-format)). When the first endpoint is deprecated, implement via a small shared Flask helper so handlers stay consistent with the policy. +4. **Server log** — Route handlers log `logging.warning()` with the deprecated symbol and recommended replacement. +5. **Removal** — Remove no earlier than **one minor version** after the deprecation was announced (e.g. deprecated in `1.2.0`, removable from `1.3.0`). Document under `### Removed` in the changelog. + +## Header format + +This project currently documents a **simplified custom format** for pre-1.0. It does not match [IETF `Deprecation`](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-deprecation-header) (HTTP-date value, not `true`) or [RFC 8594](https://www.rfc-editor.org/rfc/rfc8594) (separate `Sunset` and `Link` headers). Adopt the standards-aligned form below when the shared Flask helper lands or at `1.0.0`. + +**Current (custom, pre-1.0):** + +```http +Deprecation: true; sunset=2026-09-01 +``` + +- `sunset=` — ISO 8601 calendar date (UTC) when removal is scheduled, embedded in the `Deprecation` value. + +**Target (standards-aligned)** — emit as **separate headers** from Flask: + +```http +Deprecation: Tue, 01 Sep 2026 00:00:00 GMT +Sunset: Tue, 01 Sep 2026 00:00:00 GMT +Link: ; rel="deprecation" +``` + +Migration notes use a separate **`Link`** header (RFC 8288), not a `link=` parameter on `Deprecation`. + +Clients should treat any deprecation signal as a prompt to migrate before the sunset date. + +## Surfaces covered + +| Surface | Signals | +|---------|---------| +| HTTP endpoint or parameter | Deprecation headers, changelog entry, server log | +| JSON response field | Changelog entry; field remains until removal (no in-band signal today; future: `X-Deprecated-Fields` header or `_deprecated` envelope key) | +| CLI flag | `(deprecated)` in `--help`, changelog entry | + +## Removal documentation + +Removals go under `### Removed` in [CHANGELOG.md](../CHANGELOG.md): what was removed, which version deprecated it, and the migration path. diff --git a/pyproject.toml b/pyproject.toml index ea79f67..fb927ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,6 +79,7 @@ include = [ "launcher.py", "requirements.txt", "README.md", + "docs/", "DEPLOYMENT.md", "LICENSE", "cursor-browser.spec",