docs/sdk-release-lifecycle.md
Rama main · réplica de lectura del repositorio original.
# SDK release lifecycle
Policy for every published CueCrux SDK package. In this repo:
`@cuecrux/client` (npm, `sdks/typescript/`), `cuecrux-client` (PyPI,
`sdks/python/`) and `cuecrux-adapters` (PyPI, `integrations/adapters/`,
depends on `cuecrux-client`). The same policy governs portfolio packages
published from other repos (`@cuecrux/engine-client`) — link here rather
than fork the rules.
This is a **policy document**: it changes how releases are made, but reading
it never publishes anything, and adopting it is gated (see "Adoption gates").
## Versioning
- **Semver, strictly.** Breaking change to a public type, function signature,
default, or wire expectation → major. Additive → minor. Fix → patch.
- SDK versions are **decoupled from the daemon version**. Daemon `v*` tags
build and package both SDKs but never receive registry-write permission.
Publishing requires an explicit `sdk-python-vX.Y.Z`,
`sdk-typescript-vX.Y.Z` or `adapters-vX.Y.Z` tag, and the tag must
exactly match the package version in `pyproject.toml`/`package.json`.
`adapters-v*` refuses to publish until its `cuecrux-client` requirement
resolves from PyPI, so release the Python SDK first.
- Each SDK declares the **API version it was generated/tested against** in
its README and in package metadata, pinned to the daemon's
`/v1/openapi.json` at the release commit. Generated clients are regenerated
per daemon release; if regeneration produces no diff, no SDK release
happens.
- Pre-1.0 (current state: both SDKs are 0.x): minor = may break, patch =
safe. Say so in the README until 1.0.
## Compatibility & deprecation
- **n−1 support**: the current and previous major (after 1.0; current and
previous *minor* while 0.x) receive fixes. Older lines get security fixes
only, for 6 months, then EOL.
- Deprecations ship as warnings one release before removal, with a
`@deprecated`/`DeprecationWarning` pointing at the replacement, and are
listed in the changelog under a dedicated heading.
- The daemon keeps wire compatibility for `n−1` SDKs: a route or field an SDK
in support depends on is not removed without a daemon major/breaking-notes
entry.
## Publish integrity (T.5)
Current state: all three publish jobs use OIDC (`sdk-python.yml` since
#180, `sdk-typescript.yml` since `0e1b4903`, `adapters.yml` publish job).
No registry token is read by any workflow. What remains is registry-side
(see "Adoption gates").
1. **npm: provenance attestation.** `npm publish --access public
--provenance` with `permissions: id-token: write` on the publish job.
Links the published tarball to the exact workflow run + commit (Sigstore),
verifiable via `npm audit signatures`. Long-lived `NPM_TOKEN` is replaced
by npm **Trusted Publishing (OIDC)** so no registry secret lives in CI.
2. **PyPI: Trusted Publishing.** Replace the `PYPI_TOKEN` + twine flow with
the `pypa/gh-action-pypi-publish` OIDC flow. PyPI side: project →
Publishing → add GitHub publisher (`CueCrux/Crux`,
`sdk-python.yml`). Generates PEP 740 attestations automatically. The
`PYPI_TOKEN`/`NPM_TOKEN` secrets are deleted after cutover.
3. **Publish only a clean, reproducible build.** Both PyPI publish jobs
upload only the artifact of a `build` job that installs nothing but the
pinned toolchain (`build==1.5.0`, `hatchling==1.31.0`), builds the sdist
and wheel twice under `SOURCE_DATE_EPOCH` (last commit time) and fails if
the two sha256 sets differ. Test dependencies (unpinned `httpx`, the
adapter frameworks) are installed only in separate jobs whose output is
never published. In `sdk-python.yml` the unit tests run in a `test` job
and `publish` needs `[test, build]`. In `adapters.yml` the `build` job is
tag-only and also runs the tag==version check and, after the upload, the
"published dependencies resolve from PyPI" dry-run;
`publish` needs `[conformance, build]` and downloads only `build`'s
artifact. The `conformance` job installs unpinned framework trees
(`crewai`, `llama-index-core`, `langchain-core`) whose transitive deps
survive its uninstall step, so its PR-time package build is never
uploaded — a compromised dependency there cannot reach `dist/` on PyPI.
Do not add token-secret publish jobs.
The publish jobs have no GitHub `environment:` gate. Adding one (e.g.
`environment: pypi`) requires changing the PyPI trusted-publisher entry to
the same environment name — it is currently blank, and a mismatch makes the
OIDC exchange fail. Operator decision; change both sides together.
## Release procedure (per SDK)
1. Bump version + changelog entry in the SDK directory (PR, normal review).
2. Regenerate from `/v1/openapi.json` if the daemon API moved; commit the
regenerated client in the same PR with the API version pin updated.
3. Tests and reproducible packaging green in PR CI. Daemon tags repeat the
build/package job but skip the publish job.
4. Push `sdk-python-vX.Y.Z`, `sdk-typescript-vX.Y.Z` or `adapters-vX.Y.Z`.
A manual dispatch is build-only and cannot publish.
5. Post-publish: `npm audit signatures` / check the PyPI attestation badge;
yank only for malware/credential incidents — broken releases are
superseded by a patch, never unpublished (matches the binary-release
supersede-never-delete rule).
Registry immutability is fail-closed. Do not use `skip-existing`: a matching
filename/version does not prove artifact identity and could hide an SDK source
change that was not accompanied by a version bump.
## Adoption gates (operator actions — nothing here is done by docs alone)
- [x] PR #172 merged (workflow-change freeze lifts).
- [x] Workflows on OIDC: `sdk-typescript.yml`, `sdk-python.yml`,
`adapters.yml` (no environment; PyPI/npm publisher environment blank).
- [ ] npm: Trusted Publisher on `@cuecrux/client` = `CueCrux/Crux`,
workflow `sdk-typescript.yml`.
- [ ] PyPI: pending publisher for `cuecrux-client` = `CueCrux/Crux`,
workflow `sdk-python.yml` (the existing publisher covers only the old
`corecrux-client` name).
- [ ] PyPI: pending publisher for `cuecrux-adapters` = `CueCrux/Crux`,
workflow `adapters.yml`.
- [ ] Delete the unused `NPM_TOKEN` repo secret after one successful
OIDC publish.
- [ ] First provenance-attested releases verified (`npm audit signatures`,
PyPI attestation present) and recorded in the release notes.