test(compat): cross-version request-compatibility against supported server contracts#407
Merged
Merged
Conversation
Base automatically changed from
maxparke/fix-state-update-backend-compat
to
next
June 17, 2026 16:41
Generalizes the #405 regression guard. Captures the requests the ADK emits (states.create/update for v1) and validates each against a window of supported server OpenAPI contracts vendored under tests/compat/server_specs/: `current` (scale-agentex main) and `min-supported` (pre-#278, which still requires task_id/agent_id in the state body). Catches the 0.13.0 class of break — a client that drops a field an older deployed server still requires. Verified: with the field-drop, states.update fails "task_id/agent_id required" against min-supported while passing current. Specs are vendored for deterministic CI (no network); refresh_specs.py re-pulls them at the SHAs in manifest.json. Advance min-supported as the oldest deployed server moves forward; extend _OPERATIONS for more ADK operations. Stacked on #405 (needs the extra_body fix so states.update passes). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
965cb0c to
44513f8
Compare
deepthi-rao-scale
approved these changes
Jun 17, 2026
max-parke-scale
added a commit
to scaleapi/scale-agentex
that referenced
this pull request
Jun 17, 2026
scale-agentex has no version axis of its own — it floats at head, and the only version concept comes from SGP's platform release. That leaves no way to name an "oldest supported server contract" for downstream consumers. Add release-please (release-type: python; conventional-commit PR titles are already enforced) so merges to main cut versioned releases: a vX.Y.Z git tag + GitHub release + CHANGELOG, bumping [project].version in pyproject.toml. Each tag is an immutable snapshot of agentex/openapi.yaml — a contract checkpoint the SDK's cross-version compat suite can pin as min-supported (scaleapi/scale-agentex-python#407), replacing the placeholder commit SHA it targets today. These releases are contract checkpoints, not a deploy gate: the server still floats at head for deploys. Seeded at 0.1.0 (matching pyproject) with bootstrap-sha at current main HEAD so the changelog starts fresh; the first feat/fix merge (or a manual workflow_dispatch) cuts the first release. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
max-parke-scale
added a commit
to scaleapi/scale-agentex
that referenced
this pull request
Jun 17, 2026
scale-agentex has no version axis of its own — it floats at head, and the only version concept comes from SGP's platform release. That leaves no way to name an "oldest supported server contract" for downstream consumers. Add release-please (release-type: python; conventional-commit PR titles already enforced) so merges to main cut versioned releases: a vX.Y.Z git tag + GitHub release + CHANGELOG. Make the contract self-describe its version so the tag and spec never drift: - src/_version.py is the single source; the FastAPI app reads it (version=__version__), so generate_openapi_spec.py emits it as info.version. - release-please bumps src/_version.py, agentex/openapi.yaml (info.version), agentex/pyproject.toml, and the root pyproject together with the tag. Each tag is thus an immutable, self-describing snapshot of agentex/openapi.yaml the SDK's cross-version compat suite can pin as min-supported (scaleapi/scale-agentex-python#407), replacing the placeholder commit SHA today. Contract checkpoints, not a deploy gate: the server still floats at head for deploys. Seeded at 0.1.0 with bootstrap-sha at current main HEAD so the changelog starts fresh; the first feat/fix merge (or workflow_dispatch) cuts the first release. Verified gen-openapi emits info.version from _version.py with no spec drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
max-parke-scale
added a commit
to scaleapi/scale-agentex
that referenced
this pull request
Jun 17, 2026
scale-agentex has no version axis of its own — it floats at head, and the only version concept comes from SGP's platform release. That leaves no way to name an "oldest supported server contract" for downstream consumers. Add release-please (release-type: python; conventional-commit PR titles already enforced) so merges to main cut versioned releases: a vX.Y.Z git tag + GitHub release + CHANGELOG. Make the contract self-describe its version so the tag and spec never drift: - src/_version.py is the single source; the FastAPI app reads it (version=__version__), so generate_openapi_spec.py emits it as info.version. - release-please bumps src/_version.py, agentex/openapi.yaml (info.version), agentex/pyproject.toml, and the root pyproject together with the tag. Each tag is thus an immutable, self-describing snapshot of agentex/openapi.yaml the SDK's cross-version compat suite can pin as min-supported (scaleapi/scale-agentex-python#407), replacing the placeholder commit SHA today. Contract checkpoints, not a deploy gate: the server still floats at head for deploys. Seeded at 0.1.0 with bootstrap-sha at current main HEAD so the changelog starts fresh; the first feat/fix merge (or workflow_dispatch) cuts the first release. Verified gen-openapi emits info.version from _version.py with no spec drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
max-parke-scale
added a commit
to scaleapi/scale-agentex
that referenced
this pull request
Jun 17, 2026
## What Adds release-please so merges to `main` cut versioned releases — a `vX.Y.Z` git tag + GitHub release + CHANGELOG — from the conventional commits already enforced here. - `release-please-config.json` — `release-type: simple`, `vX.Y.Z` tags (no component), pre-1.0 bump rules, changelog sections. - `.release-please-manifest.json` — seeds the version at `0.1.0` (matches `pyproject.toml`). - `.github/workflows/release-please.yml` — runs on `main` + `workflow_dispatch`. ## Why scale-agentex has no version axis of its own: it floats at head, and the only version concept comes from SGP's platform release. So there's no way to name an **"oldest supported server contract"** that downstream consumers can target. This gives scale-agentex its own contract version axis — each release tag is an immutable snapshot of `agentex/openapi.yaml`. The SDK's cross-version compatibility suite ([scale-agentex-python#407](scaleapi/scale-agentex-python#407)) can then pin `min-supported` to a real release tag instead of the placeholder commit SHA it uses today. **These are contract checkpoints, not a deploy gate** — the server still floats at head for deploys. The release version is a separate axis from SGP's platform version; don't read them as the same. ## Bootstrap Seeded at `0.1.0` with `bootstrap-sha` at the current `main` HEAD, so the changelog starts fresh (no history backfill). After merge, the first `feat`/`fix` PR (or a manual **workflow_dispatch**) opens the first release PR; merging it cuts the first tag. The release PR title is `chore: release …`, which passes the PR-title check. ## Next (the SGP hookup — separate) 1. Tag the built image with the release version in `build-agentex.yml` (today it's `:sha`/`:latest`) so deploys get a version handle. 2. Have SGP pin agentex by version, so "oldest supported" becomes derivable from the oldest live SGP release rather than a hand-maintained floor. - Note: tags/releases created with the default `GITHUB_TOKEN` don't trigger other workflows, so the image-on-release build (1) will need a PAT or `repository_dispatch`. ## Decision to confirm Seed version `0.1.0` (matches `pyproject.toml`). Bump to `1.0.0` instead if you want the first tag to signal contract stability. 🧑💻🤖 — posted via [Claude Code](https://claude.com/claude-code) <!-- claude-code --> <!-- greptile_comment --> <h3>Greptile Summary</h3> Adds Release Please automation for versioned Agentex contract releases on `main` and manual dispatch. Seeds the release manifest at `0.1.0`. Introduces a shared Agentex version source and wires FastAPI/OpenAPI versioning to it. Configures coordinated version bumps for Python package metadata, backend metadata, OpenAPI `info.version`, and the shared version file. <details><summary><h3>Confidence Score: 5/5</h3></summary> The changes are limited to release automation and version metadata wiring, with no blocking code issues identified. The workflow, manifest, configuration, and shared version source align with the described release process and appear safe to merge. </details> <details><summary><h3><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="20" align="absmiddle"></a> T-Rex Logs</h3></summary> **What T-Rex did** - Compared the before and after release-please configuration states; the before state had all three files absent and overall validation failing, while the after state has the files present and most checks passing, with contract checks failing for specific items. - Compared the before and after OpenAPI version wiring states; the before state showed base commit, no agentex/src/\_version.py, and no explicit version in FastAPI, with /openapi.json returning 200 OK and info.version=0.1.0, while the after state shows head commit, a defined \_\_version\_\_ in \_version.py, FastAPI(version=\_\_version\_\_), and /openapi.json returning 200 OK with info.version=0.1.0; no contract-mismatch was filed because the head imports and the app responds as expected, and OpenAPI exposes 0.1.0 from the new wiring. <a href="https://app.greptile.com/trex/runs/11426852/artifacts"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=1"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=1"><img alt="View all artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=1" height="32"></picture></a> <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <!-- greptile_failed_comments --> <details open><summary><h3>Comments Outside Diff (1)</h3></summary> 1. General comment <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **Release-please package metadata and pre-major patch bump setting contradict the claimed contract** - **Bug** - The head release-please configuration is present and parseable, but it does not semantically match the requested contract for versioned contract checkpoint releases. In `release-please-config.json`, the root package is configured with `release-type: "python"` and `package-name: "agentex"` instead of the claimed `release-type: "simple"` and `package-name: "contract-checkpoints"`. The same config also sets `bump-patch-for-minor-pre-major` to `false`, while the validation objective expected the pre-1.0 bump boolean to be enabled. The executed after artifact reports these exact failed checks while the before artifact shows the config was absent on base. - **Cause** - Changed lines in `release-please-config.json` implement package metadata and bump behavior that target the Python package (`agentex`) rather than the claimed simple contract-checkpoint release package, and disable patch bumps for minor pre-major changes. - **Fix** - Update `release-please-config.json` so the root package uses `"release-type": "simple"`, `"package-name": "contract-checkpoints"`, and set `"bump-patch-for-minor-pre-major": true` if the intended contract is the one described in the PR/validation objective. If the actual intended release is the Python package release, update the PR description and release contract accordingly. <sub><a href="https://www.greptile.com/trex"><img alt="T-Rex" src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg" height="14" align="absmiddle"></a> Ran code and verified through T-Rex</sub> </details> <!-- /greptile_failed_comments --> <sub>Reviews (4): Last reviewed commit: ["ci: add release-please for versioned, se..."](4fd3813) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=38185565)</sub> <!-- /greptile_comment --> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A cross-version request-compatibility harness in
tests/compat/. It captures the requests the ADK actually emits (v1:states.create/states.update) and validates each against a window of supported server OpenAPI contracts vendored undertests/compat/server_specs/:current—scale-agentexmainmin-supported— pre-Fix missing imports in sync-openai-agents template #278, which still requirestask_id/agent_idin the state body (the exact contract the 0.13.0 client broke)Why
A per-PR test comparing the client to its own spec can't catch this class — both come from the same Stainless spec and always agree. The break only shows against an older deployed server contract. So the harness validates the client's requests against the oldest contract still in the field; a client that drops a required field fails against
min-supported, forcing coordination before release.Verified it has teeth: with the
extra_bodyfix removed,states.updatefails "'task_id'/'agent_id' is a required property" againstmin-supportedwhile passingcurrent.How it works
refresh_specs.pyre-pulls them at the SHAs inmanifest.json.respx(reusing fix(adk): re-send task_id/agent_id in state updates for backend compatibility #405's pattern); each operation declares the spec path/method its body must satisfy.Maintenance
min-supported(edit the SHA inmanifest.json, runrefresh_specs.py) as the oldest deployed server moves forward._OPERATIONSto cover more ADK operations.Notes
Stacked on #405 — needs the
extra_bodyfix sostates.updatepasses; retarget tonextonce #405 lands. The two vendored specs are large (data); the logic lives intest_request_compat.py.Out of scope (follow-ups): response-side compat (client parsing older server responses), more ADK operations, a live-deployment
/openapi.jsoncheck.🧑💻🤖 — posted via Claude Code
Greptile Summary
tests/compatrequest-compatibility harness for ADK state operations.states.createandstates.updaterequests and validates them against vendored current and minimum-supported server OpenAPI contracts.Confidence Score: 5/5
The changes are test-only compatibility coverage and do not alter runtime client behavior.
No code defects were identified in the changed harness or vendored fixtures, and the tests are scoped to validating emitted request bodies against supported server contracts.
What T-Rex did
Reviews (2): Last reviewed commit: "test(compat): validate ADK requests agai..." | Re-trigger Greptile