Skip to content

fix(reporting): read each package offering snapshot from get_media_buys - #1765

Merged
bokelley merged 2 commits into
nextfrom
claude/issue-1695-package-offering-snapshot
Nov 1, 2026
Merged

bokelley merged 2 commits into
nextfrom
claude/issue-1695-package-offering-snapshot

Conversation

@bokelley

@bokelley bokelley commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Loose end from the reporting-subscriptions DX plan.

Problem

On the managed seller path, without a SubscriptionOptions.buy_offerings hook, each package's offering set came from packages[].reporting_delivery_offering_ids or every. An empty snapshot ([]) was treated as absent, so the package was reported by every offering the service registered.

In AdCP 3.3.0-beta.3, get_media_buys carries this snapshot on every package of a seller that serves media_buy.reporting_subscriptions. It is fixed when the package is confirmed, and [] means no offering applies.

Fix

  • The snapshot is read as served, including [].
  • Only a package served without a snapshot falls back to every registered offering. This matches the TypeScript SDK (Array.isArray(snapshot) ? snapshot : every).
  • The SubscriptionOptions docstring and the two seller guides now describe the snapshot.

Tests

tests/test_reporting_subscription_managed.py:

  • A snapshot naming the registered offering owes obligations.
  • An empty snapshot owes none. This case fails before the fix.
  • A snapshot naming another offering owes none.
  • A package without a snapshot still falls back to every registered offering.

22 passed. ruff and mypy are clean.

🤖 Generated with Claude Code

Without a buy_offerings hook, the managed path treated an empty
packages[].reporting_delivery_offering_ids snapshot as absent and reported
the package by every registered offering. In 3.3.0-beta.3 a seller serving
subscriptions includes the snapshot on every package, fixed at confirmation,
and [] means no offering applies. The snapshot is now honoured as served,
including [], and only a package served without one falls back to every
registered offering, matching the TypeScript SDK.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — clean, correct bug fix.

This PR fixes the managed seller path where package.get("reporting_delivery_offering_ids") or every collapsed a present-but-empty snapshot [] into "every registered offering." The new _package_offering_ids helper uses an isinstance(..., (list, tuple)) guard so an explicit [] is honored as "no offering" and only a missing snapshot falls back to every. This aligns managed.py with coverage.py's existing semantics and matches AdCP 3.3.0-beta.3 / the TS SDK.

Checked:

  • fix: prefix is correct — no public model-shape change, no semver signal issue.
  • Covered by a parametrized test over all three snapshot cases plus the missing-snapshot fallback.
  • Docs updated consistently.
  • No high-risk paths, no gated paths, no author team gate.

No blocking or medium findings. Falls through to row 9 → approve.

The producer row-upload test stamps its worker lease with the settling
harness clock, fixed at 2026-11-01T02:10Z, while the row store checks the
lease against the database's clock_timestamp. Once the wall clock passed that
instant plus the lease, every run failed with STATE_UNAVAILABLE: no live
worker lease covers this row upload, on next and on every pull request. The
test now runs its turn at the wall clock, so the lease lies in the real
future.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit ae15bab)

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — clean test-only fix, no blocking or medium findings.

This PR's delta is a 5-line, test-only change in tests/conformance/reporting/test_reporting_row_storage_object_pg.py: the object-staging test now stamps the injected clock at datetime.now(timezone.utc) before run_worker(), because the worker lease is validated against the database's clock_timestamp() and the harness's fixed instant could sit in the past. The reviewer confirms this is the correct fix, with a load-bearing explanatory comment and no downstream time-advancement logic depending on the fixed instant in this single-turn test.

Checks:

  • No critical/high/medium findings (rows 1, 4, 5, 8 do not fire).
  • gated_paths: false and review_decision: APPROVED (row 2 n/a).
  • high_risk: false; no deleted/modified high-risk entries (rows 3, 5 n/a).
  • No no-auto-approve team match (row 7 n/a).
  • Prior decision was approve, not escalate (row 6 n/a).

Falls through to row 9 → approve.

@bokelley
bokelley merged commit 131b9ba into next Nov 1, 2026
41 checks passed
@bokelley
bokelley deleted the claude/issue-1695-package-offering-snapshot branch November 1, 2026 22:12
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.

1 participant