Repository navigation
[RFC] Spec-Aligned SDK Versioning and Branch Lifecycle #909
Description
RFC: Spec-Aligned SDK Versioning and Branch Lifecycle
Related Specs: UCP Issue #800 (Standardized Intermediate Representation Strategy for UCP), UCP Issue #817 (Decoupling SDK Data Transfer Objects from JSON Schema Semantic Validation), UCP Issue #484 (UCP Open Source Unified Toolchain and SDK Generation)
1. Summary
This RFC aligns the versioning, git branching, and release lifecycle of official UCP SDKs (python-sdk, js-sdk) directly with the Universal Commerce Protocol specification (ucp). Currently SDKs use SemVer and maintain a manual mapping in documentation from SDK version to corresponding UCP schema version.
To improve this, SDK generation will adopt the specification's two-channel model:
- Git-Native
draftChannel (main/HEAD): Themainbranch of each SDK repository tracksucpmain(draft), validating continuous model generation against evolving draft schemas in CI without publishing pre-release artifacts to package registries. - Pinned Release Channel (
release/YYYY-MM-DD/ tagvYYYY-MM-DD): Official specification releases (with a support floor ofv2026-04-08) map 1:1 to a matchingrelease/YYYY-MM-DDbranch andvYYYY-MM-DDgit tag in each SDK repository, published to package managers (PyPI and npm) using date-stamped CalVer (YYYYMMDD.0.0, e.g.,20260825.0.0).
2. Problem Statement
2.1 Indirection Between Specification Versions and SDK Versions
The UCP specification versions releases by date (v2026-04-08, v2026-08-25) alongside an active draft branch (main). By contrast, python-sdk and js-sdk currently publish under arbitrary 0.x.y minor lines (0.4.x, 0.5.x) and rely on manual compatibility tables in each repository's README.md:
UCP Spec Channel (ucp) |
python-sdk PyPI (pyproject.toml) |
python-sdk Git Tags |
js-sdk npm (package.json) |
js-sdk Git Tags |
|---|---|---|---|---|
draft (main / HEAD) |
(Not tracked; main pinned to 2026-08-25) |
(None) | (Not tracked; main pinned to 2026-08-25) |
(None) |
v2026-08-25 (release/2026-08-25) |
0.5.0 (0.5.x) |
v2026-08-25 |
0.5.0, 0.5.1 (0.5.x) |
v0.5.0, v0.5.1 |
v2026-04-08 (release/2026-04-08) |
0.4.0–0.4.6 (0.4.x) |
v2026-04-08, v2026-04-08-1..6 |
0.4.0–0.4.6 (0.4.x) |
v0.4.0..v0.4.6 |
This indirection creates three operational issues:
- Opaque Dependency Declarations: A developer inspecting
"@ucp-js/sdk": "^0.5.0"orucp-sdk==0.4.6cannot tell which UCP protocol revision (2026-08-25vs.2026-04-08) their application targets without consulting external documentation. - Tagging Divergence Across SDKs:
python-sdktags releases with specification dates (v2026-08-25) while settingversion = "0.5.0"inpyproject.toml, whereasjs-sdktags releases withv0.5.0andv0.5.1. - No
draftVisibility or Historical Branch Maintenance: Neither SDK repository maintainsrelease/YYYY-MM-DDbranches. Instead,mainin both SDKs hardcodesref: release/2026-08-25in.github/workflows/tests.yml. As a result, schema changes onucpmain(draft) are not continuously verified against SDK code generation until a release cut occurs, and patching an older supported spec release (v2026-04-08) cannot be done from a dedicated release branch.
3. Proposed Versioning & Branching Architecture
In Universal-Commerce-Protocol/ucp, main (HEAD) sets ucp_version: "draft" in mkdocs.yml, and cutting a release/YYYY-MM-DD branch triggers .github/workflows/release-setup.yml to rewrite ucp_version: "draft" to ucp_version: "YYYY-MM-DD".
With ucp-schema generate-types (python-sdk#101, js-sdk#87) eliminating hand-maintained SDK schema preprocessors, python-sdk and js-sdk can mirror ucp's exact branch and version lifecycle:
flowchart LR
subgraph "Universal-Commerce-Protocol/ucp"
UcpMain["main (ucp_version: draft)"]
UcpRel["release/YYYY-MM-DD (tag: vYYYY-MM-DD)"]
UcpMain -->|"Cut release branch"| UcpRel
end
subgraph "SDK Repositories (python-sdk, js-sdk)"
SdkMain["main (DEFAULT_VERSION=draft)<br/>Git-native only (0.0.0-draft / 0.0.0.dev0)"]
SdkRel["release/YYYY-MM-DD (tag: vYYYY-MM-DD)<br/>Published to PyPI & npm (YYYYMMDD.0.0)"]
SdkMain -->|"release-setup.yml"| SdkRel
end
UcpMain ==>|"generate_models.sh draft"| SdkMain
UcpRel ==>|"generate_models.sh YYYY-MM-DD"| SdkRel
3.1 Two-Channel Specification Mapping
We establish a support floor of v2026-04-08 (releases prior to v2026-04-08 remain archived as-is) and apply the unified scheme across two channels:
| Dimension | draft Channel (main / HEAD — Git-Native Only) |
Pinned Release Channel (release/YYYY-MM-DD / tag vYYYY-MM-DD) |
|---|---|---|
| UCP Spec Source | ucp branch main (draft / HEAD) |
ucp branch release/YYYY-MM-DD (tag vYYYY-MM-DD) |
| SDK Git Branch | main |
release/YYYY-MM-DD (e.g., release/2026-08-25, release/2026-04-08) |
| SDK Git Tag | None (git-native main / HEAD) |
vYYYY-MM-DD (e.g., v2026-08-25; SDK-only hotfixes: v2026-08-25.1) |
| Package Registry Publishing | Not published to npm or PyPI (consumed via git: github:Universal-Commerce-Protocol/js-sdk#main or git+https://github.com/Universal-Commerce-Protocol/python-sdk@main) |
Published to npm & PyPI (YYYYMMDD.0.0, e.g., 20260825.0.0; hotfix 20260825.0.1) |
generate_models.sh Default |
DEFAULT_VERSION="draft" (./generate_models.sh or ./generate_models.sh draft clones ucp@main) |
DEFAULT_VERSION="YYYY-MM-DD" (./generate_models.sh clones ucp@release/YYYY-MM-DD) |
CI model-drift Target |
Checks out Universal-Commerce-Protocol/ucp@main and verifies ./generate_models.sh draft |
Checks out Universal-Commerce-Protocol/ucp@release/YYYY-MM-DD and verifies ./generate_models.sh YYYY-MM-DD |
js-sdk (package.json) |
"version": "0.0.0-draft" on main (git-only; guarded from npm publish) |
"version": "YYYYMMDD.0.0" (e.g., 20260825.0.0; hotfix 20260825.0.1) published to npm |
python-sdk (pyproject.toml) |
version = "0.0.0.dev0" on main (git-only; guarded from PyPI publish) |
version = "YYYYMMDD.0.0" (e.g., 20260825.0.0; hotfix 20260825.0.1) published to PyPI |
3.2 Package Manager Version Format (YYYYMMDD.MAJOR.PATCH)
Because npm demands strict 3-part SemVer (X.Y.Z without leading zeroes) and PyPI demands PEP 440 version identifiers, compact integer date formatting (YYYYMMDD.0.0) provides identical version strings across both registries:
YYYYMMDD(Major): The canonical UCP specification release date (e.g.,20260825forv2026-08-25,20260408forv2026-04-08). Standard dependency ranges (^20260825.0.0in npm,~=20260825.0in Python) automatically accept non-breaking SDK updates for that exact specification release while preventing silent upgrades across specification releases.0(Minor): Reserved for backwards-compatible SDK feature additions targeting the same specification release (e.g.,20260825.1.0).0(Patch): Incremented for SDK-only bug fixes, generator patches, or dependency updates against the same specification release (20260825.0.1, tagged in git asv2026-08-25.1).
3.3 Why draft Remains Git-Native Initially
Keeping draft (main) git-native while publishing only official vYYYY-MM-DD releases to PyPI and npm offers a clean starting boundary:
- Zero Registry Noise: Every commit to
ucpmaindoes not trigger package registry churn or require pre-release dist-tag management. - Zero Version Bump Churn on
main:mainpermanently stays at0.0.0-draft(package.json) and0.0.0.dev0(pyproject.toml) withDEFAULT_VERSION="draft". - Reversible Decision (Two-Way Door): If demand emerges for pre-built
@draftregistry packages in the future, CI can publish0.0.0-draft.<sha>to the npm@draftdist-tag and0.0.0.dev<N>to PyPI without changing the branching or release-versioning model.
3.4 Relationship to ucp-schema Compiler Versioning (SemVer 1.x.y)
While language SDKs (python-sdk, js-sdk) embed a generated snapshot of a specific UCP specification release and therefore use specification-aligned date versions (vYYYY-MM-DD / YYYYMMDD.0.0), the ucp-schema CLI and library retains standard 3-part SemVer (1.x.y, published to Crates.io via Release Please):
- Version-Independent Toolchain:
ucp-schemais the schema-agnostic compiler, resolver, validator, and linter. It does not bundle a fixed snapshot of UCP schema; instead, it accepts any specification tree (v2026-04-08,v2026-08-25, ordraft) or.well-known/ucpprofile URL as input at invocation time. Its SemVer (1.4.1→1.5.0) tracks the capabilities of the UCP JSON Schema dialect and CLI (lint,resolve,compose,validate,generate-types,generate-openapi). - Backwards-Compatibility Contract Across Spec Releases (
>= v2026-04-08): Because bothucpCI (ucp-schema lint source/) and SDKmodel-driftworkflows install the latest1.xrelease ofucp-schemafrom Crates.io,ucp-schema1.xmaintains backwards compatibility across all supported specification branches (v2026-04-08,v2026-08-25, anddraft). In particular,ucp-schema lintrestricts error diagnostics (E001–E008, exit code1) to foundational JSON Schema and UCP annotation invariants that hold across all supported releases, while introducing newly added hygiene checks as non-failing warnings (W002–W007, exit code0unless--strictis passed).
4. Automated Release Workflow (release-setup.yml)
Both python-sdk and js-sdk will adopt a .github/workflows/release-setup.yml workflow modeled directly on ucp/.github/workflows/release-setup.yml:
- Trigger: Creation of a branch matching
refs/heads/release/YYYY-MM-DD. - Version Extraction: Parses
VERSION=${GITHUB_REF_NAME#release/}(e.g.,2026-08-25) andCALVER=${VERSION//-/}(e.g.,20260825). - Branch Pinning & Regeneration:
- Rewrites
DEFAULT_VERSION="draft"toDEFAULT_VERSION="$VERSION"ingenerate_models.sh. - Rewrites
ref: maintoref: release/$VERSIONin.github/workflows/tests.yml. - Sets package version to
${CALVER}.0.0inpyproject.tomlorpackage.json. - Executes
./generate_models.sh "$VERSION"usingucp-schema generate-typesand commits the resulting models and manifest back torelease/$VERSION.
- Rewrites
- Release Publishing Guard (
.github/workflows/release.yml):- Adds a pre-publish check verifying that the package version matches
^[0-9]{8}\.[0-9]+\.[0-9]+$(rejecting0.0.0-draftand0.0.0.dev0) before publishing to PyPI or npm.
- Adds a pre-publish check verifying that the package version matches
5. Execution Plan
- Release
ucp-schemav1.5.0and Land SDK Migrations: Mergeucp-schema#81–#88, then mergepython-sdk#101andjs-sdk#87against the currentrelease/2026-08-25baseline. - Cut Pinned Release Branches (
release/2026-08-25andrelease/2026-04-08): inpython-sdkandjs-sdk. - Configure
mainasdraftand Addrelease-setup.yml: Updatemainin both SDK repositories sogenerate_models.shdefaults todraft(ucp@main), setpyproject.tomlto0.0.0.dev0andpackage.jsonto0.0.0-draft, add.github/workflows/release-setup.yml, and replace the manual0.x.ylookup tables inREADME.md.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriage / Unscheduled
Activity