Skip to content

feat(reporting): serve the reference seller standalone and pass the TypeScript storyboard - #1776

Merged
bokelley merged 7 commits into
nextfrom
claude/issue-1695-reference-seller
Nov 1, 2026
Merged

bokelley merged 7 commits into
nextfrom
claude/issue-1695-reference-seller

Conversation

@bokelley

@bokelley bokelley commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

PR 6 of the reporting-subscriptions DX plan: a Python reference seller for reporting subscriptions on the managed path. Stacked on #1774 (P12, which adds the reference seller and its controller as the test kit's default).

Standalone server

python -m adcp reference-seller reporting --port 3000 (or python examples/reporting_subscriptions_seller.py) serves a sandbox:

  • MCP at /mcp and A2A at /. The both transport runs the startup hook that opens the reporting service.
  • The bearer token names the principal, and storyboard-buyer is used without one.
  • Storage is process-local, with ADCP_ENV=development set by the entry point.
  • The virtual clock starts at --start (default: now) and moves only through comply_test_controller.
  • --backfill-on-regrant is available.

The controller serves seed_media_buy and every reporting_subscription_probe operation (spec #8621), behind a sandbox-authority account resolver that admits only the seller's sandbox accounts:

  • revoke_grant;
  • regrant (returns chain, authorized_at and regranted_at);
  • reduce_grant;
  • set_account_timezone (returns previous_timezone and the cutovers);
  • advance_time (runs the worker at every period boundary crossed).

So it serves the scenario the TS T17 owed_periods_match check will drive. The cross-SDK interop harness can run this server as is.

Cross-SDK check, run locally. The TypeScript runner (adcp-client main, 478be1ee) passed every step against this server:

$ adcp storyboard run http://127.0.0.1:39123/mcp --file reporting-subscriptions.yaml \
    --auth storyboard-buyer --allow-http --compliance-version 3.3.0-beta.3
✅ 15 passed, 0 failed, 0 skipped
✅ strict: 11/11 passed

The same storyboard, in process

  • tests/fixtures/storyboards/reporting-subscriptions.yaml is vendored from adcp-client examples/storyboards/reporting-subscriptions.yaml (PR #3534), pinned to commit eeeb370d by SHA-256.
  • tests/storyboard_runner.py is a minimal YAML runner for the checks this storyboard uses: response_schema against the bundled schemas, field_value, field_present, field_absent, field_contains, field_equals_context, error_code, plus context_outputs and $generate:uuid_v4#name. It is test-only; Python ships no runner.

tests/test_reporting_reference_seller.py:

  • The reference seller passes all 15 steps in process over MCP.
  • Negative control: a seller whose sync_principal and get_principal readbacks drop prior_versions fails. It fails exactly apply_version_2, read_back_version_2 and omit_subscription, and every failing check's path is under prior_versions[0]. The TS control lists two steps, because its runner skips the context comparison in read_back_version_2; this runner fails it too.
  • The probe over MCP covers seeding a buy, advance_time, the periods served versus the buyer's reconcile (owed periods match), revoke_grant showing in accounts_unauthorized, regrant with a continued chain, set_account_timezone and reduce_grant.
  • Bearer tokens map to principals, and the CLI wiring is checked.

Managed-path fixes the storyboard surfaced

The reference seller's get_adcp_capabilities failed response validation until these were fixed:

  • The managed path's adcp.principal block lacked the required optimistic_concurrency. It is now true; the principal runtime enforces expected_configuration_version.
  • It always added reporting_destinations without max_reporting_destinations, reporting_destination_offerings and suspension_interval_seconds, which the schema then requires. It now adds that section only when the seller's own block carries those facts, the same as TS (prepareReportingDestination).

The managed suite is updated and green.

Docs: the testing guide gains The reference seller, and the seller guide points to it.

🤖 Generated with Claude Code

…ypeScript storyboard

python -m adcp reference-seller reporting, and
examples/reporting_subscriptions_seller.py, serve the reference seller as a
sandbox server: MCP at /mcp and A2A at /, the bearer token naming the
principal, a virtual clock moved only through comply_test_controller, and a
controller serving seed_media_buy and every reporting_subscription_probe
operation behind a sandbox-account gate. The TypeScript storyboard runner
passes its reporting_subscriptions storyboard against it, all 15 steps with
strict schema checks.

The same storyboard, vendored from adcp-client and pinned by digest, now
runs in process over MCP through a minimal YAML runner, with the negative
control that drops prior_versions from the readback and fails exactly the
steps that read it. A test drives the probe over MCP and checks that the
periods the seller planned match what a buyer computes.

Two managed-path fixes the storyboard surfaced: the principal capability
block now advertises optimistic_concurrency true, and advertises
reporting_destinations only when the seller supplies the destination facts
the schema requires with it, so get_adcp_capabilities validates.

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 review, no blocking or medium findings.

Checked: this PR is one feat(reporting) commit adding a standalone reference seller (serve_reference_reporting_seller, bearer-token principal), an in-process storyboard runner (211 lines, fails closed), a 608-line hash-pinned vendored storyboard, tests, and one production fix to managed.py::advertise_principal. The production change is sound and tested: optimistic_concurrency: true is enforced at server/principal.py:715, and reporting_destinations is advertised only when schema-required facts are present (fail-closed, keeps the advertisement valid). The reworked chain logic in testing/reporting.py:522 correctly ties "continued" to a chain start strictly before the latest grant, with the empty-grants guard intact at :516.

No Critical/High/Medium findings. high_risk=false, gated_paths=false, no no-auto-approve team match, no prior decision. None of decision rows 1–8 fire → row 9 approve.

@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 delta on the seller-reference-server set.

No critical or high findings. One medium finding exists (src/adcp/reporting/subscriptions/receipts.py:215 — inspection error code not unwrapped, surfacing "ReportingInspectionCode.X" instead of the clean code in report.receipts.failed), but the reviewer notes this change arrived via merges of parent/stacked branches and is NOT part of PR #1776's own 10-file GitHub diff. Even counting it, a single medium with no escalation trigger (no gated paths unsatisfied — review_decision is APPROVED; high_risk false; not data-loss/schema/infra category; no team gate) falls through the decision table to row 9.

Prior decision was approve; this subsequent pass confirms the seller-reference-server set remains clean. events.py doorbell-before-poll race fix has coverage; the testing get_media_buys split fails loudly on reconcile paths as intended.

Decision table: rows 1–8 do not fire (1 medium only, not 3+; medium category is not data-loss/schema/infra; gated_paths false; no deletions; high_risk false; no team gate) → row 9 approve.

Medium findings

  • src/adcp/reporting/subscriptions/receipts.py:215 — Inspection error code not unwrapped; built-in refusals surface as "ReportingInspectionCode.X" in report.receipts.failed

@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 — subsequent pass on PR #1776 (reporting-subscriptions reference seller + in-process storyboard runner).

No blocking findings. The current run surfaced no new Critical/High/Medium findings, and the delta is clean:

  • advertise_principal (managed.py:1098) now fail-closes reporting_destinations behind the three schema-required facts and always advertises reporting_subscriptions + optimistic_concurrency — a correctness/validation improvement over always-advertising.
  • chain computation (testing/reporting.py:559) correctly replaces the old degenerate ("new" if ... else "new") ternary and matches the regrant-continues-chain test.
  • Largest delta file storyboard_runner.py (211 lines) is sound: resolve_path fan-out and _error_code fallback (L1030-1039) handle the storyboard checks safely.
  • reporting-subscriptions.yaml is a vendored fixture pinned by sha256 (test_reporting_reference_seller.py:19).
  • CLI/serve wiring matches accepting signatures.

Prior Medium (receipts.py:215, inspection error code not unwrapped) lies outside this delta and was not re-evaluated per Medium scope rules.

Gates: high_risk=false, gated_paths=false, review_decision=APPROVED, no no-auto-approve team match. Prior decision was approve. No decision-table trigger fires → row 9 approve.

@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 — focused set of tested bug fixes with no blocking findings.

This is a subsequent pass over the delta since a prior clean approve. The reviewer found no Critical/High/Medium findings. The changes are a focused set of tested bug fixes (engine.py _state_at removed-period schedule computation for #1770; coverage.py _offering_zone timezone validation deferral for #1769; resolution.py deferring missing_standard_dimensions to _is_candidate for #8679; service.py _managed_caller fallback + supported_versions injection for managed sellers #1771). Each change pairs with a passing test and validation surfaces are preserved.

Gate checks:

  • No no-auto-approve team match.
  • gated_paths: false (and review_decision is APPROVED regardless).
  • high_risk: false.
  • No critical/high/medium findings → decision table rows 1–8 do not fire; falls through to row 9 (approve).

Prior decision was itself an approve, so no sticky-escalation concern applies.

@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 pass, no blocking or medium findings.

This delta adds the reporting-subscriptions reference seller: a standalone MCP server, a vendored (sha256-pinned) storyboard, an in-process runner, and capability fixes for #1771. The change is additive — no public export removed or retyped.

Checks confirmed by the reviewer:

  • _managed_caller (service.py:1617-1635) resolves the account from the request only when the caller is authenticated; _get_reporting_status's require_subscription_grant scopes every read by consumer_id — no cross-tenant leak.
  • advertise_principal (managed.py:1098-1120) gates reporting_destinations on the three schema-required facts and removes it otherwise — fail-closed; regenerated capability validates (test_reporting_subscription_managed.py:1436).
  • inject_capabilities advertises supported_versions (minus -rc aliases) so 3.3-beta.3 is reachable.
  • storyboard_runner.py:1071-1154 is a test-only helper; vendored storyboard YAML is sha256-pinned to the TS source (test at :1257).

Gate status: high_risk false, gated_paths false (and review_decision APPROVED regardless), no no-auto-approve team match. Prior decision was approve; this subsequent run surfaces no new findings. No decision-table trigger fires → row 9 approve.

Base automatically changed from claude/issue-1695-p12-test-kit to next November 1, 2026 22:14
@bokelley
bokelley merged commit 76812b8 into next Nov 1, 2026
41 checks passed
@bokelley
bokelley deleted the claude/issue-1695-reference-seller branch November 1, 2026 22:15
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