Repository navigation
ci(release): cut 10.0.0-beta.N pre-releases from next - #1672
Merged
Merged
Conversation
…iver the ones already stuck in the queue (#1651) PgWebhookDeliverySupervisor never sent a task webhook (#1606). send_mcp stored the task status (completed, failed, ...) in status_str, while the worker only claimed rows whose status_str was 'pending' or 'retry', so every job enqueued through send_mcp stayed unsent. A row that was claimed and then retried after a transport error would also have gone out with status "retry". Queue state now lives in a new delivery_state column; status_str keeps the task status the payload carries. create_schema() migrates an existing table with ADD COLUMN IF NOT EXISTS delivery_state TEXT NOT NULL DEFAULT 'pending', which marks every row already in the queue deliverable without touching its task status. No worker ever claimed those rows, so each is sent once, oldest first. During a rolling deploy, rows an older process enqueues take the same default, and an older worker (still claiming on status_str) never picks up a row this version writes. The old status_str work index is dropped. The worker also fixes the idempotency_key before a fresh send and persists it when it reschedules, so a retry after a transport error reuses the key instead of minting a new one. A replay that raised keeps the bytes it was replaying. send_mcp persists an enum status as its wire value. Release note: adopters running PgWebhookDeliverySupervisor will see task webhooks that were stuck in adcp_webhook_delivery_queue delivered after upgrading; inspect or delete them first if they should not go out (docs/webhooks/pg-delivery-supervisor.md). Closes #1606. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n pin (#1650) #1634 repeats the deferred #1538. It bumps the exact datamodel-code-generator pin (0.64 -> 0.81) without regenerating src/adcp/types/, and edits the frozen reporting interop requirement files under scripts/ci/reporting_interop/python/, which breaks those controls. Add a pip entry for the interop directory that ignores every dependency, matching the npm entry from #1590, and pip and uv entries for the root that ignore datamodel-code-generator. Version updates stay off (open-pull-requests-limit: 0); ignore rules also apply to security updates. Generator upgrades are an SDK 10 decision (docs/v10-codegen-plan.md, #1649). Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Pin the published, cosign-verified AdCP 3.2.7 release (schemas/releases/3.2.7.json: source 8d1d3244, certificate identity release.yml@refs/heads/3.2.x, measured byte counts and SHA-256 of all four artifacts) and refresh the 3.2 cache, the packaged compliance bundle and the generated sources through the stock --require-signed-release synchronization and regeneration chain. 3.2.5 through 3.2.7 are compliance-storyboard releases. The one schema change is 3.2.6's `x-removed-in: "4.0.0"` marker on the 43 deprecated fields scheduled for removal in AdCP 4.0 (annotation only: no field, type or requirement changes). The generator's version-envelope normalization compared an inline `adcp_major_version` copy against the envelope's declaration modulo documentation keys, so the new marker on the envelope made `SearchBrandsRequest` fall out of `AdcpVersionEnvelope`; treat `x-removed-in` as documentation so the hierarchy is unchanged. The generated types otherwise differ only in the example `$schema` URLs, and the field-shape delta is empty. Ship the 3.2.7 compliance bundle and release pin in the wheel and sdist alongside the retained 3.2.1 and 3.2.4 trees. Replace the 3.2.4 adoption test with a 3.2.7 one and keep a focused immutable 3.2.4 historical test; point the live-pin assertions, the request-signing vector manifest and the task-message lattice refs at 3.2.7. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…ed array (#1658) Validating a schema-valid McpWebhookPayload or AsyncResponseData raised ``TypeError: Unable to apply constraint 'min_length' ... object of type 'Losses' has no len()`` instead of returning a model or a ValidationError (#1616). An array schema that carries an ``allOf`` of ``contains``/``if``-``then`` constraints (``losses`` on the legacy purchase continuation, ``refinements`` on refine_proposals_request, ``results`` on refine_proposals_response) has no Python shape codegen can give those keywords, so datamodel-code-generator renders the composition as an empty object model and widens the field to ``list[Item] | Empty``. Pydantic applies the array's min_length/max_length to the whole union, and a dict reaching the model arm trips the constraint with a raw TypeError. Add a generic post-generation rule, drop_empty_model_arms_from_array_fields, that strips every empty AdCPBaseModel arm from a union that also carries a ``list[...]`` arm. The class itself stays, since it is a public adcp.types name and removing it would be a 9.x surface change for nothing. The existing fix_legacy_purchase_accepted_losses stays as the model-specific validator injection it also performs. Tests: the four bundle examples of core/mcp-webhook-payload.json validate both as written and in the completed form the sweep grades; a dict on each affected field is a ValidationError; the generated tree carries no empty-model arm beside a list. Remove the two schemas from the round-trip sweep's REFUSING allowlist, and add a guard that no schema-valid document may make a generated model raise anything but ValidationError. Closes #1616 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…d transition graph (#1664) A seller that mirrors status from its ad server needs two things the SDK did not publish (#1604): the terminal statuses, which every adopter rederived from MEDIA_BUY_TRANSITIONS, and the moves it may record from its platform, which are not all moves a buyer may request. adcp.decisioning.state_machines now exports: - MEDIA_BUY_TERMINAL_STATUSES, derived from the graph (completed, canceled, rejected), and is_terminal_media_buy_status(), which returns False for a status the spec does not define (draft, pending_approval). - OBSERVED_MEDIA_BUY_TRANSITIONS, a strict superset of MEDIA_BUY_TRANSITIONS, and is_observable_media_buy_transition(). The extra edges are the three AdCP 3.2 published edges that follow from the seller's lifecycle rather than from a status a buyer asks for: pending_creatives -> active, pending_creatives -> paused and pending_start -> paused (3.2.7 lifecycle.mdx "Creative sync timing" and transition diagram; specification.mdx on the latent create-time hold). The result equals the graph the @adcp/client storyboard runner's status.monotonic invariant enforces for 3.2. The issue's other moves (active -> pending_start, completed -> active or paused) have no AdCP 3.2 edge, and the specification says terminal states allow no further transitions, so the observed graph leaves them out and the docstrings say why. There is no CREATIVE_TERMINAL_STATUSES: every creative status can move on. MEDIA_BUY_TRANSITIONS and assert_media_buy_transition are unchanged; media_buy_actions reuses the new terminal constant. Docs: docs/media-buy-state-machine.md. Tests cover the derivation, the spec enum, the published graph, unknown and unchanged statuses, and the generated MediaBuyStatus enum; an adopter type-check fixture covers the new surface. Closes #1604 Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nchronous business transactions (#1665) PgNotificationOutbox.enqueue_prepared only accepted a psycopg 3 AsyncConnection, so a seller whose business writes run on synchronous SQLAlchemy, psycopg2 or psycopg 3 could not queue a notification in the same transaction as the change it announces (#1607). enqueue_prepared_sync takes the same arguments and accepts a psycopg 3 Connection, a psycopg2 connection, or a SQLAlchemy Connection on either driver (session.connection() for an ORM unit of work). The pure work moves into _prepare_insert (validation, _protected, _scope, _aad, AES-GCM, deadline) and _existing_binding_id (the duplicate-binding check), which both methods call; only the two statements differ. Transaction detection per driver, refused with ValueError before any SQL: - psycopg 3 and psycopg2: the session must be in a transaction block (INTRANS), the async method's rule. - SQLAlchemy: in_transaction() must be true and the driver connection must not be in autocommit (AUTOCOMMIT isolation). SQLAlchemy begins the driver transaction on the first statement, so the notification may be the first write. Any other object, including a psycopg AsyncConnection, raises TypeError. Driver dispatch reads sys.modules, so no optional driver is imported. Both paths now ask the driver for tuple rows. An adopter connection with row_factory=dict_row made enqueue_prepared fail with KeyError: 0 on main. Tests against real PostgreSQL, for psycopg 3, psycopg2, and SQLAlchemy on each: the row commits with the business write and the existing async worker (a fresh outbox instance) delivers the same PreparedWebhook; a rollback leaves neither row and delivers nothing; sync and async share one binding (identical re-enqueue returns the id, different headers raise, the transaction stays usable); per-driver refusal outside a transaction; SQLAlchemy enqueue-first, AUTOCOMMIT refusal and Session use; dict-row connections on all three paths. Docs section and an adopter type-check fixture. Closes #1607 Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: aao-ipr-bot[bot] <279263549+aao-ipr-bot[bot]@users.noreply.github.com>
Forward-ports main through v9.3.0 (2bbe334) into next with a true merge: the signed AdCP 3.2.7 adoption (#1657), the codegen empty-arm fix (#1658), #1650, #1651, #1664 and #1665. Conflicts: next keeps its 3.3.0-beta.0 wire pin; main's 3.2.7 becomes the 3.2 preview bundle (PREVIEW_VERSIONS), its compliance package and release pin ship beside 3.3.0-beta.0 (MANIFEST.in, package-data), and main's 3.2.7 adoption test becomes the installed-3.2-contract test (tests/test_adcp_3_2_7_historical.py) beside main's 3.2.4 historical test. Generated types are regenerated from the 3.3.0-beta.0 bundle with main's codegen fix (4 files). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
SDK 10 targets AdCP 3.3; with the signed 3.3.0-beta.0 bundle adopted, next leaves the alpha channel. release-please-config.next.json now sets prerelease-type: beta, the release-channel contract test and RELEASING.md follow, and the 10.0.0-alpha.0 proposal (#1533) is superseded. next also releases its SDK 10 companion: adcp-reporting-storage is a second component (0.2.0-beta.N, CHANGELOG.next.md, its own release PR and publish run), the normalizer accepts its release PR, release-publish.yml publishes it from next, and the #1605 companion gate runs for every adcp publish on both lines instead of being skipped on next. Release-As: 10.0.0-beta.0 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — release-engineering PR with no blocking findings.
This PR cuts 10.0.0-beta.N from next and forward-ports main through 9.3.0. The reviewer found no Critical/High/Medium findings.
What was checked:
- Genuinely new work (release-please-config.next.json beta channel + second adcp-reporting-storage component, release-please-next.yml, release-publish.yml companion-gate widening, dependabot ignore entries, pyproject normalizer) faithfully mirrors main's proven two-component setup, including the correct bare-vs-path-prefixed output asymmetry.
- Tests (test_release_configuration.py, test_normalize_pyproject_prerelease.py) are updated to assert every new fact — CI gates stay armed.
- Forward-ported source (webhook supervisor delivery_state split, idempotency-key fix, enqueue_prepared_sync, state-machine exports) carries additive feat/fix commits with no mislabeled breaking change on the public surface.
- delivery_state migration uses a constant DEFAULT (metadata-only, no table rewrite) — no data-loss concern.
Decision table: No critical/high/medium findings. gated_paths is false, so row 2 does not fire. high_risk is true but all high_risk_reasons are (modified) schema-cache files with no medium-or-higher finding attached — rows 3 and 5 do not fire. No author team gate, no prior decision. None of rows 1–8 match → row 9 approve.
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.
SDK 10 targets AdCP 3.3; with the signed 3.3.0-beta.0 bundle adopted (#1662) and main synced through 9.3.0 (#1671),
nextleaves the alpha channel.release-please-config.next.json:prerelease-type: beta; the channel contract test (test_release_please_keeps_next_on_the_beta_channel) andRELEASING.mdfollow. The10.0.0-alpha.0proposal (chore(next): release 9.0.0 #1533) is closed as superseded.nextalso releases its SDK 10 companion:adcp-reporting-storageis a second Release Please component onnext(0.2.0-beta.N, tagsadcp-reporting-storage-v0.2.0-beta.N, changelogpackages/adcp-reporting-storage/CHANGELOG.next.md, manifest entry, its own release PR and publish dispatch inrelease-please-next.yml); the normalizer acceptsnext's storage release PR;release-publish.ymlpublishes the storage component fromnext; and the ci(release): refuse an adcp release its companion packages can't install with #1605 companion gate now runs for everyadcppublish on both lines instead of being skipped onnext. chore(reporting-storage): cut 0.2.0-beta.N pre-releases from next #1663 (storage-only, merged withRelease-As: 0.2.0-beta.0) seeds that line, so the firstadcp10.0.0-beta.0publish passes the gate oncenext's storage release is on PyPI.Merge order after this lands: Release Please opens two release PRs on
next; merge and publishadcp-reporting-storage 0.2.0-beta.0first, thenadcp 10.0.0-beta.0(its companion gate requires the storage release on PyPI). One outside step: addnextto therelease-publishenvironment's deployment branches.Squash-merge with the body ending in the footer below: Release Please reads
Release-Asfrom the squash commit.Release-As: 10.0.0-beta.0
🤖 Generated with Claude Code