Repository navigation
feat(reporting): serve the reference seller standalone and pass the TypeScript storyboard - #1776
Conversation
…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>
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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-closesreporting_destinationsbehind the three schema-required facts and always advertisesreporting_subscriptions+optimistic_concurrency— a correctness/validation improvement over always-advertising.chaincomputation (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_pathfan-out and_error_codefallback (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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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'srequire_subscription_grantscopes every read byconsumer_id— no cross-tenant leak.advertise_principal(managed.py:1098-1120) gatesreporting_destinationson the three schema-required facts and removes it otherwise — fail-closed; regenerated capability validates (test_reporting_subscription_managed.py:1436).inject_capabilitiesadvertisessupported_versions(minus-rcaliases) 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.
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(orpython examples/reporting_subscriptions_seller.py) serves a sandbox:/mcpand A2A at/. Thebothtransport runs the startup hook that opens the reporting service.storyboard-buyeris used without one.ADCP_ENV=developmentset by the entry point.--start(default: now) and moves only throughcomply_test_controller.--backfill-on-regrantis available.The controller serves
seed_media_buyand everyreporting_subscription_probeoperation (spec #8621), behind a sandbox-authority account resolver that admits only the seller's sandbox accounts:revoke_grant;regrant(returnschain,authorized_atandregranted_at);reduce_grant;set_account_timezone(returnsprevious_timezoneand the cutovers);advance_time(runs the worker at every period boundary crossed).So it serves the scenario the TS T17
owed_periods_matchcheck 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:The same storyboard, in process
tests/fixtures/storyboards/reporting-subscriptions.yamlis vendored from adcp-clientexamples/storyboards/reporting-subscriptions.yaml(PR #3534), pinned to commiteeeb370dby SHA-256.tests/storyboard_runner.pyis a minimal YAML runner for the checks this storyboard uses:response_schemaagainst the bundled schemas,field_value,field_present,field_absent,field_contains,field_equals_context,error_code, pluscontext_outputsand$generate:uuid_v4#name. It is test-only; Python ships no runner.tests/test_reporting_reference_seller.py:sync_principalandget_principalreadbacks dropprior_versionsfails. It fails exactlyapply_version_2,read_back_version_2andomit_subscription, and every failing check's path is underprior_versions[0]. The TS control lists two steps, because its runner skips the context comparison inread_back_version_2; this runner fails it too.advance_time, the periods served versus the buyer'sreconcile(owed periods match),revoke_grantshowing inaccounts_unauthorized,regrantwith a continued chain,set_account_timezoneandreduce_grant.Managed-path fixes the storyboard surfaced
The reference seller's
get_adcp_capabilitiesfailed response validation until these were fixed:adcp.principalblock lacked the requiredoptimistic_concurrency. It is nowtrue; the principal runtime enforcesexpected_configuration_version.reporting_destinationswithoutmax_reporting_destinations,reporting_destination_offeringsandsuspension_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