Skip to content

test(compat): cross-version request-compatibility against supported server contracts#407

Merged
max-parke-scale merged 1 commit into
nextfrom
maxparke/compat-spec-conformance
Jun 17, 2026
Merged

test(compat): cross-version request-compatibility against supported server contracts#407
max-parke-scale merged 1 commit into
nextfrom
maxparke/compat-spec-conformance

Conversation

@max-parke-scale

@max-parke-scale max-parke-scale commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

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 under tests/compat/server_specs/:

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_body fix removed, states.update fails "'task_id'/'agent_id' is a required property" against min-supported while passing current.

How it works

Maintenance

  • Advance min-supported (edit the SHA in manifest.json, run refresh_specs.py) as the oldest deployed server moves forward.
  • Extend _OPERATIONS to cover more ADK operations.

Notes

Stacked on #405 — needs the extra_body fix so states.update passes; retarget to next once #405 lands. The two vendored specs are large (data); the logic lives in test_request_compat.py.

Out of scope (follow-ups): response-side compat (client parsing older server responses), more ADK operations, a live-deployment /openapi.json check.

🧑‍💻🤖 — posted via Claude Code

Greptile Summary

  • Adds a tests/compat request-compatibility harness for ADK state operations.
  • Captures emitted states.create and states.update requests and validates them against vendored current and minimum-supported server OpenAPI contracts.
  • Includes pinned server spec fixtures, a manifest, and a refresh helper for updating the vendored 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.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the compat harness in the before state to capture the base command, commit, pytest output, and EXIT_CODE: 5 with no tests run.
  • Reran the compat harness after applying changes, capturing the head, commit, four parametrized compat cases, and EXIT_CODE: 0.
  • Executed the compatibility regression test with the unmutated head and confirmed all four compat cases pass.
  • Executed the compatibility regression test after introducing a temporary missing-field mutation and observed only states.update-min-supported failing with agent_id and task_id required-property errors, while states.update-current and both create cases pass.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (2): Last reviewed commit: "test(compat): validate ADK requests agai..." | Re-trigger Greptile

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>
@max-parke-scale max-parke-scale merged commit 862c539 into next Jun 17, 2026
39 checks passed
@max-parke-scale max-parke-scale deleted the maxparke/compat-spec-conformance branch June 17, 2026 17:01
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants