From c0fed55e0f5c93cbc1439363845e643511362cb1 Mon Sep 17 00:00:00 2001 From: Thom Ezechiels Date: Fri, 11 Sep 2026 11:11:23 +0200 Subject: [PATCH 1/3] docs: add SDK regeneration and release workflow --- docs/8_sdk_generation.md | 199 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 docs/8_sdk_generation.md diff --git a/docs/8_sdk_generation.md b/docs/8_sdk_generation.md new file mode 100644 index 00000000..91780c3c --- /dev/null +++ b/docs/8_sdk_generation.md @@ -0,0 +1,199 @@ +# SDK generation and release workflow + +The clients under `sdk/` are generated from the Zero Friction OpenAPI specifications in `openapi_specs/`. Regeneration must be reproducible, reviewed as generated code, and tested against dependent projects before it is merged into `main`. + +## Versioning baseline + +The current SDK on `main` is the **v1 baseline** and should be tagged `v1` before replacing the generated clients with a newer Zero Friction API snapshot. + +The next full regeneration from newer OpenAPI specifications is intended to become **v1.1** once it has been validated in dependent projects and merged into `main`. + +Do not move an existing release tag to newer code. A release tag identifies the exact SDK state that downstream projects were tested against. + +## Source of truth + +The repository contains eight OpenAPI specifications and eight generated Python clients: + +| OpenAPI specification | Generated client | Python package | +| --- | --- | --- | +| `Attachments-1-0.yaml` | `sdk/attachments_client` | `attachments_client` | +| `Billing-1-0.yaml` | `sdk/billing_client` | `billing_client` | +| `Communication-1-0.yaml` | `sdk/communication_client` | `communication_client` | +| `Configuration-1-0.yaml` | `sdk/configuration_client` | `configuration_client` | +| `Forecasting-1-0.yaml` | `sdk/forecasting_client` | `forecasting_client` | +| `Masterdata-1-0.yaml` | `sdk/masterdata_client` | `masterdata_client` | +| `Metering-1-0.yaml` | `sdk/metering_client` | `metering_client` | +| `RegionalRegulations-1-0.yaml` | `sdk/regionalregulations_client` | `regionalregulations_client` | + +The version in the OpenAPI `info.version` field is not sufficient to identify whether Zero Friction changed the specification. Zero Friction can publish changed specifications while retaining the same API version number. Always treat the downloaded YAML files themselves as the source snapshot. + +## Generator version + +Use the same OpenAPI Generator version as the current generated SDK unless a generator upgrade is an explicit part of the change. The current clients were generated with OpenAPI Generator `7.13.0`. + +Keeping the generator version fixed prevents generator-template changes from being mixed with actual API-specification changes. + +## Branch-first workflow + +Never regenerate all clients directly on `main`. + +Create a dedicated branch from the current `main` first: + +```bash +git switch main +git pull +git switch -c chore/regenerate-sdk-v1.1 +``` + +Before changing the specifications, ensure the current `main` commit that represents the existing SDK has been tagged as `v1`. + +Then update the relevant files under `openapi_specs/` with the newly downloaded specifications from the Zero Friction developer documentation. + +Commit the specification files and regenerated clients together so the generated code can always be traced back to the exact specification snapshot that produced it. + +## Regenerating one client + +Run OpenAPI Generator from the repository root. Docker is preferred because it pins the generator version without requiring a local Java/OpenAPI Generator installation. + +For example, to regenerate the Configuration client: + +```bash +docker run --rm \ + -v "$PWD:/local" \ + openapitools/openapi-generator-cli:v7.13.0 generate \ + -i /local/openapi_specs/Configuration-1-0.yaml \ + -g python \ + -o /local/sdk/configuration_client \ + --package-name configuration_client +``` + +The output directory is intentionally the existing generated client directory. OpenAPI Generator will update generated source files, models, API classes, documentation and generator metadata in place. + +## Regenerating the complete SDK + +For a complete Zero Friction API refresh, regenerate all eight clients from the repository root: + +```bash +set -euo pipefail + +GENERATOR_VERSION="7.13.0" + +while IFS='|' read -r spec output package; do + docker run --rm \ + -v "$PWD:/local" \ + "openapitools/openapi-generator-cli:v${GENERATOR_VERSION}" generate \ + -i "/local/openapi_specs/${spec}" \ + -g python \ + -o "/local/sdk/${output}" \ + --package-name "${package}" +done <<'EOF' +Attachments-1-0.yaml|attachments_client|attachments_client +Billing-1-0.yaml|billing_client|billing_client +Communication-1-0.yaml|communication_client|communication_client +Configuration-1-0.yaml|configuration_client|configuration_client +Forecasting-1-0.yaml|forecasting_client|forecasting_client +Masterdata-1-0.yaml|masterdata_client|masterdata_client +Metering-1-0.yaml|metering_client|metering_client +RegionalRegulations-1-0.yaml|regionalregulations_client|regionalregulations_client +EOF +``` + +After generation, inspect the result before making any manual compatibility changes: + +```bash +git status +git diff --stat +git diff +``` + +Pay particular attention to: + +- renamed or removed generated models; +- changed method signatures; +- newly required parameters; +- removed fields or enum members; +- changed response types; +- changes to authentication/header parameters; +- generated file additions and deletions. + +Do not edit generated code merely to make the diff smaller. If compatibility code is needed, prefer implementing it in the hand-maintained `zero_friction/` package or document explicitly why a generated file must be patched. + +## Validate the SDK branch + +Run the repository checks after regeneration: + +```bash +uv lock +uv sync +uv run pre-commit run --all-files +uv run pytest +``` + +Generated clients are part of the product even when root lint/type-check settings exclude some generated files. A successful generation is not enough: the unified `zero_friction/` package and repository tests must still work. + +## Test dependent projects before merge + +The regeneration branch is the integration target until all known consumers have been checked. + +Point a dependent project temporarily at the branch instead of `main`, for example: + +```text +git+https://github.com/TECHLETES/zero_friction.git@chore/regenerate-sdk-v1.1 +``` + +For every dependent repository: + +1. install the SDK from the regeneration branch; +2. run its full test suite and relevant integration/smoke tests; +3. search for imports of renamed or removed generated models; +4. check calls whose generated signatures changed; +5. fix the dependent repository or add deliberate compatibility support in `zero_friction`; +6. record that the repository has been validated against the candidate SDK. + +Do not merge the SDK regeneration into `main` until the dependent projects that rely on it have been validated or an explicit migration plan exists for them. + +## Pull request and release + +Once the SDK branch and dependent projects are validated: + +1. make sure the branch contains the new OpenAPI specifications and all regenerated SDK output; +2. run the repository checks again; +3. open a pull request from the regeneration branch to `main`; +4. describe API additions, breaking SDK-surface changes and downstream validation in the PR; +5. merge only after review and CI pass; +6. tag the merged `main` commit as `v1.1`. + +The intended release sequence is therefore: + +```text +current main ------------------------------> tag: v1 + \ + chore/regenerate-sdk-v1.1 + ├── update OpenAPI specs + ├── regenerate all SDK clients + ├── validate zero_friction + ├── validate dependent repos + └── PR -> main -------------------> tag: v1.1 +``` + +## Installing a stable or candidate version + +Stable consumers should prefer a release tag instead of tracking `main`: + +```bash +pip install "git+https://github.com/TECHLETES/zero_friction.git@v1" +``` + +After the regenerated SDK is merged and tagged: + +```bash +pip install "git+https://github.com/TECHLETES/zero_friction.git@v1.1" +``` + +During compatibility testing only, install from the regeneration branch: + +```bash +pip install "git+https://github.com/TECHLETES/zero_friction.git@chore/regenerate-sdk-v1.1" +``` + +Using tags for production/dependent projects prevents an unrelated future commit to `main` from silently changing the SDK version being installed. From 3609b291067a6be4102e6fcbf057e8cf08353448 Mon Sep 17 00:00:00 2001 From: Thom Ezechiels Date: Fri, 11 Sep 2026 11:11:40 +0200 Subject: [PATCH 2/3] docs: link SDK generation workflow --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index baf59677..ffe854a9 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,12 @@ Install the SDK directly from GitHub: pip install "git+https://github.com/TECHLETES/zero_friction.git@main" ``` +For stable consumers, prefer an explicit release tag once available, for example: + +```bash +pip install "git+https://github.com/TECHLETES/zero_friction.git@v1" +``` + For repository development, use the supported uv workflow: ```bash @@ -52,6 +58,7 @@ print(contract) ```text sdk/ Generated, independently installable API clients +openapi_specs/ Zero Friction OpenAPI specification snapshots zero_friction/ Unified client and shared SDK logic tests/ Repository tests scripts/ Adoption and pre-commit helper scripts @@ -59,6 +66,14 @@ scripts/ Adoption and pre-commit helper scripts .github/workflows/ CI, labeling, and staging checks ``` +## SDK regeneration and releases + +Do not regenerate the clients directly on `main`. OpenAPI specification updates are made on a dedicated branch, all affected clients are regenerated with the pinned OpenAPI Generator version, and dependent repositories are validated against that branch before the changes are merged. + +The current SDK is the `v1` baseline. A validated full regeneration from the newer Zero Friction OpenAPI specifications is intended to become `v1.1` after merge to `main`. + +See [docs/8_sdk_generation.md](docs/8_sdk_generation.md) for the complete generation, compatibility-testing, branch and release workflow. + ## Development checks Dependencies are declared in `pyproject.toml` and locked in `uv.lock`: @@ -75,4 +90,4 @@ and pip-audit. Generated clients are preserved as product code and excluded from root-package lint/type-check coverage settings. See `docs/quickstart.md` and the documents under `docs/` for the development, -secret-management, dependency, quality, and devcontainer workflows. +secret-management, dependency, quality, devcontainer, and SDK generation workflows. From 2b8878a0b22299d86c447e00e4df335de34082cf Mon Sep 17 00:00:00 2001 From: Thom Ezechiels Date: Fri, 11 Sep 2026 11:11:57 +0200 Subject: [PATCH 3/3] docs: reference SDK regeneration workflow --- CONTRIBUTING.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ac29faf..211f7ce3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,6 +58,21 @@ uv run pytest Commit with a clear message. Pre-commit runs automatically and may modify files; stage those changes and commit again if needed. +## SDK generation + +Changes to the Zero Friction OpenAPI specifications or generated clients follow a separate branch-first compatibility workflow. Do not regenerate SDK clients directly on `main`. + +When updating the SDK: + +- update the OpenAPI specification snapshots under `openapi_specs/`; +- regenerate the affected clients under `sdk/` with the pinned OpenAPI Generator version; +- inspect generated model, method-signature and response-type changes; +- run the Zero Friction SDK test suite; +- validate dependent repositories against the regeneration branch before merge; +- merge through a pull request and create the planned release tag only after downstream validation succeeds. + +See [docs/8_sdk_generation.md](docs/8_sdk_generation.md) for the complete commands, branch workflow, compatibility-testing process and release/versioning convention. + ## Dependencies Edit `pyproject.toml` from the devcontainer, then update and commit the lock