Skip to content

update_media_buy: implement revision → CONFLICT optimistic concurrency (deferred from #1546) #1607

Description

@numarasSigmaSoftware

Summary

update_media_buy does not implement the revision optimistic-concurrency field. The pinned AdCP spec (3.1.0-beta.3) makes this a MUST: per media-buy/update-media-buy-request.json and the SDK type (adcp==5.7.0 UpdateMediaBuyRequest.revision):

"Expected current revision for optimistic concurrency. When provided, sellers MUST reject the update with CONFLICT if the media buy's current revision does not match. Obtain from get_media_buys or the most recent update response."

This was the one part of the envelope-tolerance review on #1546 (Blocker 3) intentionally deferred, because — unlike the sibling fixes (context echo, idempotency-key preservation) that shipped in that PR — it is a migration-bearing concurrency feature, not a mechanical change.

Current state (as of #1546)

  • There is no revision column on the MediaBuy ORM model, and no compare logic.
  • revision is currently stripped by the envelope-tolerance layer (ADCP_ENVELOPE_FIELDS in src/core/request_compat.py) because no wrapper / request model declares it, so update_media_buy(revision=N, ...) reaches the impl with revision=None.
  • _update_media_buy_impl never consults revision.

Net effect: a buyer that pins revision for safe concurrent editing gets a silent success instead of the spec-mandated CONFLICT on a stale write.

Scope / acceptance criteria

  1. Migration — add a revision integer column to MediaBuy (Alembic; non-empty upgrade()/downgrade(), single head). Initialize existing rows to 1.
  2. Plumb the field — declare revision on the update_media_buy MCP wrapper, A2A raw/handler, and the internal UpdateMediaBuyRequest, so the envelope-tolerance middleware no longer strips it (it strips only ADCP_ENVELOPE_FIELDS a tool does not declare).
  3. Enforce transactionally — in the update path, compare the request's revision against the media buy's current revision under the same transaction; raise a typed CONFLICT on mismatch; increment the stored revision on success.
  4. Echo revision — return the current revision on the update_media_buy response, and on get_media_buys responses (the spec names both as the source of the next expected revision).
  5. Tests — mismatch → CONFLICT wire envelope; matching revision → success + increment; concurrent-update race (two updates carrying the same stale revision → the second gets CONFLICT). Mutation-verify each pin. Cite the authoritative schema (dist/schemas/3.1.0-beta.3/media-buy/update-media-buy-request.json) and note whether the conformance storyboard grades it.

Related (lower priority)

Full idempotency replay-dedup for sync_accounts. #1546 restored end-to-end preservation of the client idempotency_key, but _sync_accounts_impl still does not consult it for dedup (the idempotency_attempt repository already exists). Wiring replay-dedup here is a natural companion to the revision work.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Ready for Dev

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions