Skip to content
Merged
  •  
  •  
  •  
33 changes: 33 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,36 @@ updates:
open-pull-requests-limit: 0
ignore:
- dependency-name: "*"

# Frozen Python environments for the same interop replay. Each requirements
# file pins the installed set an interop control verifies, so it changes only
# with its control.
- package-ecosystem: pip
directory: "/scripts/ci/reporting_interop/python"
schedule:
interval: monthly
open-pull-requests-limit: 0
ignore:
- dependency-name: "*"

# The SDK's own Python dependencies. Version updates stay off, so these
# entries exist only for their ignore rules, which also apply to security
# updates. datamodel-code-generator is pinned exactly because its class
# numbering shifts between releases: an upgrade must regenerate
# src/adcp/types/ in the same change, which is an SDK 10 decision
# (docs/v10-codegen-plan.md, #1649). Dependabot has filed this manifest as
# pip, and uv.lock makes it a uv project too, so both carry the rule.
- package-ecosystem: pip
directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 0
ignore:
- dependency-name: "datamodel-code-generator"
- package-ecosystem: uv
directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 0
ignore:
- dependency-name: "datamodel-code-generator"
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ jobs:
tests/test_decisioning_lazy_pg_stores.py \
tests/conformance/decisioning/test_pg_task_webhook_outbox.py \
tests/conformance/decisioning/test_pg_notification_outbox.py \
tests/conformance/decisioning/test_pg_webhook_delivery_supervisor.py \
tests/test_notification_outbox.py \
tests/test_notification_outbox_artifacts.py \
tests/conformance/decisioning/test_pg_reference_workflow_queue.py \
Expand Down
15 changes: 11 additions & 4 deletions .github/workflows/release-please-next.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Release Please (next)

# Draft-spec line copy of main's release-please.yml. It runs from next only,
# opens release PRs against next with next's own config and manifest, and
# queues next's copy of release-publish.yml. Releases are 10.0.0-alpha.N
# pre-releases of adcp only: the adcp-reporting-storage component is released
# from main, and next's config excludes its path. main's release flow, config,
# queues next's copy of release-publish.yml. Releases are 10.0.0-beta.N
# pre-releases of adcp and 0.2.0-beta.N pre-releases of adcp-reporting-storage
# (SDK 10's companion), each from its own component. main's release flow, config,
# and manifest are unchanged; this file and next's config and manifest are
# inert on main and are removed when next merges into main at ratification.
# See RELEASING.md.
Expand Down Expand Up @@ -55,10 +55,17 @@ jobs:
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PROPOSAL_PRS: ${{ steps.release.outputs.prs }}
- name: Queue publication for the created release
- name: Queue publication for the created adcp release
if: steps.release.outputs.release_created == 'true'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_SHA: ${{ steps.release.outputs.sha }}
RELEASE_TAG: ${{ steps.release.outputs.tag_name }}
run: gh workflow run release-publish.yml --ref next -f package=adcp -f release_sha="$RELEASE_SHA" -f tag_name="$RELEASE_TAG"
- name: Queue publication for the created adcp-reporting-storage release
if: steps.release.outputs['packages/adcp-reporting-storage--release_created'] == 'true'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_SHA: ${{ steps.release.outputs['packages/adcp-reporting-storage--sha'] }}
RELEASE_TAG: ${{ steps.release.outputs['packages/adcp-reporting-storage--tag_name'] }}
run: gh workflow run release-publish.yml --ref next -f package=adcp-reporting-storage -f release_sha="$RELEASE_SHA" -f tag_name="$RELEASE_TAG"
12 changes: 6 additions & 6 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ jobs:
# adcp tags are vX.Y.Z; the storage component tags carry its name.
case "$PACKAGE" in
adcp) [[ "$RELEASE_TAG" =~ ^v[0-9] ]] ;;
# Only main releases the storage component; next cuts adcp alphas.
adcp-reporting-storage) [[ "$GITHUB_REF_NAME" = main && "$RELEASE_TAG" =~ ^adcp-reporting-storage-v[0-9] ]] ;;
# main releases the SDK 9 storage line; next releases its SDK 10 beta.
adcp-reporting-storage) [[ "$RELEASE_TAG" =~ ^adcp-reporting-storage-v[0-9] ]] ;;
*) echo "unknown package $PACKAGE" >&2; exit 1 ;;
esac
test "$(git rev-parse "$RELEASE_TAG^{commit}")" = "$RELEASE_SHA"
Expand All @@ -77,11 +77,11 @@ jobs:
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: '3.12'
# Only main's stable adcp releases are gated on the companions: next cuts
# adcp pre-releases that adopters opt into with --pre, and the storage
# distribution's adcp-10 release is cut from main at ratification.
# Every adcp release, on main and on next, needs a published companion
# that installs with it: next publishes its own adcp-reporting-storage
# pre-release (0.2.0-beta.N, adcp>=9.0.0,<11) before the first 10.0.0-beta.
- name: Require installable companion distributions for an adcp release
if: inputs.package == 'adcp' && github.ref == 'refs/heads/main'
if: inputs.package == 'adcp'
run: |
python -m pip install packaging
version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
".": "9.2.0",
".": "9.3.0",
"packages/adcp-reporting-storage": "0.1.0-beta.4"
}
3 changes: 2 additions & 1 deletion .release-please-manifest.next.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
".": "9.0.0-beta.3"
".": "9.0.0-beta.3",
"packages/adcp-reporting-storage": "0.1.0-beta.4"
}
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,21 @@
change public consumer defaults. See
[format-kind migration](docs/canonical-format-kinds-migration.md).

## [9.3.0](https://github.com/adcontextprotocol/adcp-client-python/compare/v9.2.0...v9.3.0) (2026-10-27)


### Features

* **decisioning:** export media-buy terminal statuses and the observed transition graph ([#1664](https://github.com/adcontextprotocol/adcp-client-python/issues/1664)) ([4b1554e](https://github.com/adcontextprotocol/adcp-client-python/commit/4b1554e14de0e72bf21af8a6a2b3f102a1227a5b)), closes [#1604](https://github.com/adcontextprotocol/adcp-client-python/issues/1604)
* **webhooks:** add PgNotificationOutbox.enqueue_prepared_sync for synchronous business transactions ([#1665](https://github.com/adcontextprotocol/adcp-client-python/issues/1665)) ([e081fe4](https://github.com/adcontextprotocol/adcp-client-python/commit/e081fe431d83c733648921d34ead9420d0cbce4b)), closes [#1607](https://github.com/adcontextprotocol/adcp-client-python/issues/1607)


### Bug Fixes

* **protocol:** adopt signed AdCP 3.2.7 on SDK 9 ([#1657](https://github.com/adcontextprotocol/adcp-client-python/issues/1657)) ([95ed163](https://github.com/adcontextprotocol/adcp-client-python/commit/95ed163d61c40a851997280c647ef8627ada17b0))
* **types:** drop the empty-model arm codegen emits beside a constrained array ([#1658](https://github.com/adcontextprotocol/adcp-client-python/issues/1658)) ([adaf29b](https://github.com/adcontextprotocol/adcp-client-python/commit/adaf29bcb040860d8d4047741735002ea527016f)), closes [#1616](https://github.com/adcontextprotocol/adcp-client-python/issues/1616)
* **webhooks:** send PgWebhookDeliverySupervisor task webhooks and deliver the ones already stuck in the queue ([#1651](https://github.com/adcontextprotocol/adcp-client-python/issues/1651)) ([83a2fe3](https://github.com/adcontextprotocol/adcp-client-python/commit/83a2fe37e8517950c4aa465ad0d5b92a955bf16c))

## [9.2.0](https://github.com/adcontextprotocol/adcp-client-python/compare/v9.1.1...v9.2.0) (2026-10-26)


Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ recursive-include src/adcp/reporting/materializer/assets *.json
recursive-include src/adcp/_compliance/3.2.1 *.json *.jsonl *.yaml *.md
recursive-include src/adcp/_compliance/3.2.4 *.json *.jsonl *.yaml *.md
recursive-include src/adcp/_compliance/3.3.0-beta.0 *.json *.jsonl *.yaml *.md
recursive-include src/adcp/_compliance/3.2.7 *.json *.jsonl *.yaml *.md
# build_py copies the tracked cache into wheels. Do not duplicate those
# inputs with ignored, generated package copies in the source distribution.
prune src/adcp/_schemas
Expand All @@ -29,5 +30,6 @@ prune schemas/cache/3.2.0-rc.7
prune schemas/releases
include schemas/releases/3.2.1.json
include schemas/releases/3.2.4.json
include schemas/releases/3.2.7.json
include schemas/releases/3.1.27.json
include schemas/releases/3.3.0-beta.0.json
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ the SDK's supported versions in the error details.
- **[Durable legacy purchase continuations](docs/legacy-purchase-continuations.md)** - Safe products-only compatibility redemption and crash recovery
- **[Media-buy lifecycle coordinator](docs/media-buy-lifecycle-coordinator.md)** - Negotiated catalog-to-purchase workflow across AdCP 3.0, 3.1, and 3.2; remaining buyer parity is tracked in [#1154](https://github.com/adcontextprotocol/adcp-client-python/issues/1154)
- **[Media-buy action rights](docs/media-buy-action-rights.md)** - Assess product possibilities, accepted change rights, and currently available actions
- **[Media-buy state machine](docs/media-buy-state-machine.md)** - Requested and observed lifecycle graphs, and terminal statuses
- **[Testing your AdCP server](docs/testing-your-adcp-server.md)** - In-process harness for unit tests plus storyboard-runner compliance grading
- **[Universal macro translation](docs/universal-macro-translation.md)** - Producer-side pixel URL translation, trust boundary, and diagnostics
- **[Multi-tenant contract](docs/multi-tenant-contract.md)** - Scope invariants every multi-tenant agent must satisfy
Expand Down
60 changes: 34 additions & 26 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ releases ([#1525](https://github.com/adcontextprotocol/adcp-client-python/issues
| --- | --- | --- |
| `main` | Work against the latest ratified AdCP version (3.2.x today) | The current major (9.x), through release-please |
| `release/N.x` (`release/8.x`, `release/7.x`) | Fixes for an older major | Patch releases of that major, from the branch's own release workflow |
| `next` | Work against draft specs, such as AdCP 3.3 agent identity and Web Bot Auth | Pre-releases only (`10.0.0-alpha.N`), from its own release-please configuration |
| `next` | SDK 10 on AdCP 3.3 (the 3.3.0-beta.0 bundle, agent identity, Web Bot Auth) | Pre-releases only (`10.0.0-beta.N`), from its own release-please configuration |

Open a PR against the branch that carries the spec it implements. Code written
to an unratified spec (an open adcontextprotocol/adcp PR or a draft) targets
Expand Down Expand Up @@ -60,40 +60,48 @@ so that merges in either direction never change the other line's release flow:
- `.github/workflows/release-please-next.yml` runs on pushes to `next` only,
with its own concurrency group and `target-branch: next`.
- `release-please-config.next.json` sets `versioning: prerelease`,
`prerelease-type: alpha`, and `prerelease: true`, and writes
`prerelease-type: beta`, and `prerelease: true`, and writes
`CHANGELOG.next.md`. `.release-please-manifest.next.json` holds `next`'s
current version.
- The commit that added the setup ends with `Release-As: 10.0.0-alpha.0`, so
the first release is `10.0.0-alpha.0`. Every later release increments the
alpha number (`10.0.0-alpha.1`, ...), whatever the commit type. Don't
merge a `next` release PR that proposes a version without `-alpha.N`.
- The channel moved from alpha to beta with the AdCP 3.3.0-beta.0 adoption:
the commit that switched it ends with `Release-As: 10.0.0-beta.0`, so the
first SDK 10 release is `10.0.0-beta.0` (the earlier `10.0.0-alpha.0`
proposal, #1533, was closed unreleased). Every later release increments the
beta number (`10.0.0-beta.1`, ...), whatever the commit type. Don't merge a
`next` release PR that proposes a version without `-beta.N`. A `Release-As:`
footer must survive the squash: paste it into the squash commit message when
merging the PR that carries it.
- After release-please opens or updates the release PR, the workflow runs
`scripts/normalize_pyproject_prerelease --release-prs --target-branch next`
to rewrite `pyproject.toml` to PEP 440 (`10.0.0a0`). The normalizer accepts
to rewrite `pyproject.toml` to PEP 440 (`10.0.0b0`). The normalizer accepts
only `release-please--branches--next--components--adcp` PRs into `next`.
- When the release PR merges, release-please tags `v10.0.0-alpha.N`, creates a
- When the release PR merges, release-please tags `v10.0.0-beta.N`, creates a
GitHub release marked as a pre-release, and dispatches `release-publish.yml`
with `--ref next`. That workflow waits for `next`'s CI at the release commit,
then publishes to PyPI after the `release-publish` environment approval.
PyPI treats `10.0.0aN` as a pre-release: `pip install adcp` keeps resolving
PyPI treats `10.0.0bN` as a pre-release: `pip install adcp` keeps resolving
to `main`'s releases, and adopters opt in with `pip install --pre adcp` or
`adcp==10.0.0a0`.

- `next` releases `adcp` only. The `adcp-reporting-storage` component
(`packages/adcp-reporting-storage`, see `docs/releasing.md`) is released from
`main`: next's config has no storage package and excludes its path from the
root, the normalizer accepts no storage release PR into `next`, and
`release-publish.yml` refuses `package=adcp-reporting-storage` unless it runs
from `main`. On `next` the storage package's `adcp` range is
`adcp>=9.0.0bN,<11` so the workspace still installs once `next` cuts
`10.0.0aN`; when a merge from `main` moves the floor, take `main`'s floor and
keep `<11`.
`adcp==10.0.0b0`.

- `next` releases two components, like `main`: `adcp` (`10.0.0-beta.N`) and
its SDK 10 companion `adcp-reporting-storage` (`0.2.0-beta.N`, tags
`adcp-reporting-storage-v0.2.0-beta.N`, changelog
`packages/adcp-reporting-storage/CHANGELOG.next.md`). The root package
excludes the storage path, so a storage-only commit never releases `adcp`.
The storage line started with a storage-only commit ending in
`Release-As: 0.2.0-beta.0`; keep storage changes out of a root `Release-As:`
commit, or the storage package takes that version too. On `next` the storage
package's `adcp` range is `adcp>=9.0.0,<11`: the workspace must still install
while `pyproject.toml` carries `main`'s version (the release PR bumps it), and
PEP 440 treats `10.0.0b0` as inside `<11`. When a merge from `main` moves the
floor, take `main`'s floor and keep `<11`. At ratification the range narrows
to `adcp>=10.0.0,<11` and the storage line continues from `main`.
- `main`'s companion gate (`scripts/check_companion_releases.py`, #1605) runs
in `release-publish.yml` only for a publish from `main`. It refuses a stable
`adcp` release that no published `adcp-reporting-storage` release installs
with. A `next` pre-release is opt-in (`pip install --pre adcp`) and the
storage distribution's adcp-10 release is cut from `main` at ratification,
so the gate would only block every `next` release until then.
for every `adcp` publish, from `next` too. The first `10.0.0-beta.0` publish
is refused until a published `adcp-reporting-storage` release accepts
`10.0.0b0`: merge and publish `next`'s storage release PR
(`adcp-reporting-storage-v0.2.0-beta.0`) before the `adcp` one. Storage
publishes are not gated.

One-time setup: add `next` to the `release-publish` environment's deployment
branches (GitHub Settings → Environments). The PyPI Trusted Publisher needs no
Expand Down Expand Up @@ -151,7 +159,7 @@ When the draft spec that `next` tracks is ratified:
`release-please-config.json`'s channel to match (see `docs/releasing.md`).
This must be the newest `Release-As:` commit. Release-please uses the
newest footer it finds, so it overrides `next`'s earlier
`Release-As: 10.0.0-alpha.0`.
`Release-As: 10.0.0-beta.0`.
6. If the 9.x line still needs fixes, create `release/9.x` from `main`, with
its own release-please workflow like `release/8.x`'s.
7. Open a PR from `next` into `main` and merge it with **Create a merge
Expand Down
6 changes: 2 additions & 4 deletions SCHEMA_DELTAS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,5 @@

## Field changes

- `core/hold_policy.py`
- `PositiveDuration`: `+__slots__`, `+_constraints`, `+_json_schema_extra` `-root`
- `trust/v1/trust.py`
- `Domain`: `+__slots__`, `+_constraints`, `+_json_schema_extra` `-root`
- `brand/search_brands_request.py`
- `SearchBrandsRequest`: `-adcp_major_version`
3 changes: 2 additions & 1 deletion docs/handler-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -1716,7 +1716,8 @@ if event_type in subscription.event_types:

`WebhookSender` is the transport layer — it constructs and signs one HTTP POST.
`InMemoryWebhookDeliverySupervisor` adds best-effort retries and circuit breakers
for local development. Neither it nor `PgWebhookDeliverySupervisor` implements
for local development. Neither it nor
[`PgWebhookDeliverySupervisor`](webhooks/pg-delivery-supervisor.md) implements
the atomic terminal-state/outbox contract required for TaskHandoff publication;
use `PgTaskWebhookOutbox` with `PgTaskRegistry` for that lifecycle. The older
supervisors remain explicit/manual delivery utilities.
Expand Down
Loading
Loading