Skip to content

[RFC] Spec-Aligned SDK Versioning and Branch Lifecycle #909

Open

Description

@gsmith85

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:

  1. Git-Native draft Channel (main / HEAD): The main branch of each SDK repository tracks ucp main (draft), validating continuous model generation against evolving draft schemas in CI without publishing pre-release artifacts to package registries.
  2. Pinned Release Channel (release/YYYY-MM-DD / tag vYYYY-MM-DD): Official specification releases (with a support floor of v2026-04-08) map 1:1 to a matching release/YYYY-MM-DD branch and vYYYY-MM-DD git 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:

  1. Opaque Dependency Declarations: A developer inspecting "@ucp-js/sdk": "^0.5.0" or ucp-sdk==0.4.6 cannot tell which UCP protocol revision (2026-08-25 vs. 2026-04-08) their application targets without consulting external documentation.
  2. Tagging Divergence Across SDKs: python-sdk tags releases with specification dates (v2026-08-25) while setting version = "0.5.0" in pyproject.toml, whereas js-sdk tags releases with v0.5.0 and v0.5.1.
  3. No draft Visibility or Historical Branch Maintenance: Neither SDK repository maintains release/YYYY-MM-DD branches. Instead, main in both SDKs hardcodes ref: release/2026-08-25 in .github/workflows/tests.yml. As a result, schema changes on ucp main (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
Loading

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., 20260825 for v2026-08-25, 20260408 for v2026-04-08). Standard dependency ranges (^20260825.0.0 in npm, ~=20260825.0 in 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 as v2026-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:

  1. Zero Registry Noise: Every commit to ucp main does not trigger package registry churn or require pre-release dist-tag management.
  2. Zero Version Bump Churn on main: main permanently stays at 0.0.0-draft (package.json) and 0.0.0.dev0 (pyproject.toml) with DEFAULT_VERSION="draft".
  3. Reversible Decision (Two-Way Door): If demand emerges for pre-built @draft registry packages in the future, CI can publish 0.0.0-draft.<sha> to the npm @draft dist-tag and 0.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):

  1. Version-Independent Toolchain: ucp-schema is 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, or draft) or .well-known/ucp profile 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).
  2. Backwards-Compatibility Contract Across Spec Releases (>= v2026-04-08): Because both ucp CI (ucp-schema lint source/) and SDK model-drift workflows install the latest 1.x release of ucp-schema from Crates.io, ucp-schema 1.x maintains backwards compatibility across all supported specification branches (v2026-04-08, v2026-08-25, and draft). In particular, ucp-schema lint restricts error diagnostics (E001–E008, exit code 1) 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 code 0 unless --strict is 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:

  1. Trigger: Creation of a branch matching refs/heads/release/YYYY-MM-DD.
  2. Version Extraction: Parses VERSION=${GITHUB_REF_NAME#release/} (e.g., 2026-08-25) and CALVER=${VERSION//-/} (e.g., 20260825).
  3. Branch Pinning & Regeneration:
    • Rewrites DEFAULT_VERSION="draft" to DEFAULT_VERSION="$VERSION" in generate_models.sh.
    • Rewrites ref: main to ref: release/$VERSION in .github/workflows/tests.yml.
    • Sets package version to ${CALVER}.0.0 in pyproject.toml or package.json.
    • Executes ./generate_models.sh "$VERSION" using ucp-schema generate-types and commits the resulting models and manifest back to release/$VERSION.
  4. 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]+$ (rejecting 0.0.0-draft and 0.0.0.dev0) before publishing to PyPI or npm.

5. Execution Plan

  1. Release ucp-schema v1.5.0 and Land SDK Migrations: Merge ucp-schema#81–#88, then merge python-sdk#101 and js-sdk#87 against the current release/2026-08-25 baseline.
  2. Cut Pinned Release Branches (release/2026-08-25 and release/2026-04-08): in python-sdk and js-sdk.
  3. Configure main as draft and Add release-setup.yml: Update main in both SDK repositories so generate_models.sh defaults to draft (ucp@main), set pyproject.toml to 0.0.0.dev0 and package.json to 0.0.0-draft, add .github/workflows/release-setup.yml, and replace the manual 0.x.y lookup tables in README.md.

Activity

  1. added
    gov:tc-meetingNominated for synchronous discussion at an upcoming weekly DTC meeting
    on Oct 7, 2026
  2. added this to the 2026-12-08 milestone on Oct 16, 2026
  3. moved this to Triage / Unscheduled in DTC Review Pipelineon Oct 29, 2026
  4. added
    area:commonIssues and pull requests related to common protocol schemas and specifications
    on Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

RFCarea:commonIssues and pull requests related to common protocol schemas and specificationsgov:tc-meetingNominated for synchronous discussion at an upcoming weekly DTC meeting

Type

No type

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions