Module adcp.reporting.submissions.submit
Explicit low-level receipt submission with durable uncertainty semantics.
Functions
async def submit_reporting_receipts(client: ReportingReceiptSubmissionClient,
*,
authorizer: ReportingSubmissionAuthorizer,
store: ReportingSubmissionIntentStore,
receipts: Sequence[ReportingSubmissionReceipt] | None = None,
timeout_seconds: float = 30.0) ‑> ReportingSubmissionResult-
Expand source code
async def submit_reporting_receipts( client: ReportingReceiptSubmissionClient, *, authorizer: ReportingSubmissionAuthorizer, store: ReportingSubmissionIntentStore, receipts: Sequence[ReportingSubmissionReceipt] | None = None, timeout_seconds: float = 30.0, ) -> ReportingSubmissionResult: """Reserve or resume a receipt plan without replacing uncertain work. Omit ``receipts`` to resume the latest intent for the freshly authorized scope, including its completed outcomes after a lost return. Otherwise the supplied plan is frozen and atomically reserved before ANY network write. An earlier pending scope intent takes priority, with proposal_deferred=True. The caller must reconsider the deferred plan against fresh seller history. A transport failure, timeout, failed task or malformed response leaves the chunk uncertain and returns pending=True. Retry within the live protocol version uses the exact durable body and idempotency key. A pending intent from a retired version remains readable and byte-identical but is refused before transport; it is never rewritten as a new-version request. Cancellation propagates with the intent still retained. Storage failure raises a closed error; resume the stored scope because the last commit may have succeeded. There is no expiry/abandon/replacement path. Every item failure is retained alongside successes. Completion only means every submission outcome is confirmed; it does not mean every receipt was recorded, accepted, readable, or sufficient for definitive reconciliation. This API does not select history, build adjustment evidence, post consumer statuses, or modify the original reconciliation/checkpoint interfaces. """ if ( isinstance(timeout_seconds, bool) or not isinstance(timeout_seconds, (int, float)) or not isfinite(timeout_seconds) or timeout_seconds <= 0 ): raise ReportingSubmissionError(ReportingSubmissionCode.INVALID_PLAN) scope = await _authorize(client, authorizer) proposed = ( prepare_reporting_receipt_submission(scope, receipts) if receipts is not None else None ) state = await _storage(store.reserve(proposed) if proposed is not None else store.get(scope)) if state is None: raise ReportingSubmissionError(ReportingSubmissionCode.NOT_FOUND) _check_state(state, scope) deferred = proposed is not None and proposed.submission_id != state.submission_id if state.pending and state.adcp_version != _VERSION: # An unresolved older reservation retains its exact wire bytes, but # the current SDK must not issue a new request under a retired pin. raise ReportingSubmissionError(ReportingSubmissionCode.INVALID_PLAN) while state.pending: await _authorize(client, authorizer, scope) chunk = state.confirmed_chunks request = state.request(chunk) response = None try: response = await asyncio.wait_for( client.sync_reporting_receipts(request), timeout=timeout_seconds ) except Exception: response = None if response is None: return ReportingSubmissionResult( state, deferred, ReportingSubmissionCode.TRANSPORT_UNCERTAIN ) if ( response.success is not True or response.status != "completed" or not isinstance(response.data, SyncReportingReceiptsResponse) ): return ReportingSubmissionResult( state, deferred, ReportingSubmissionCode.RESPONSE_UNCONFIRMED ) invalid = False try: updated = await _storage( store.confirm(scope, state.submission_id, chunk, response.data) ) except ReportingSubmissionError as error: if error.code != ReportingSubmissionCode.INVALID_RESPONSE: raise invalid = True if invalid: return ReportingSubmissionResult( state, deferred, ReportingSubmissionCode.INVALID_RESPONSE ) _check_state(updated, scope, state) if updated.confirmed_chunks <= chunk: raise ReportingSubmissionError(ReportingSubmissionCode.HISTORY_CORRUPT) state = updated await _authorize(client, authorizer, scope) return ReportingSubmissionResult(state, deferred)Reserve or resume a receipt plan without replacing uncertain work.
Omit
receiptsto resume the latest intent for the freshly authorized scope, including its completed outcomes after a lost return. Otherwise the supplied plan is frozen and atomically reserved before ANY network write. An earlier pending scope intent takes priority, with proposal_deferred=True. The caller must reconsider the deferred plan against fresh seller history.A transport failure, timeout, failed task or malformed response leaves the chunk uncertain and returns pending=True. Retry within the live protocol version uses the exact durable body and idempotency key. A pending intent from a retired version remains readable and byte-identical but is refused before transport; it is never rewritten as a new-version request. Cancellation propagates with the intent still retained. Storage failure raises a closed error; resume the stored scope because the last commit may have succeeded. There is no expiry/abandon/replacement path.
Every item failure is retained alongside successes. Completion only means every submission outcome is confirmed; it does not mean every receipt was recorded, accepted, readable, or sufficient for definitive reconciliation. This API does not select history, build adjustment evidence, post consumer statuses, or modify the original reconciliation/checkpoint interfaces.
Classes
class ReportingReceiptSubmissionClient (*args, **kwargs)-
Expand source code
class ReportingReceiptSubmissionClient(Protocol): async def sync_reporting_receipts( self, request: SyncReportingReceiptsRequest ) -> TaskResult[SyncReportingReceiptsResponse]: ...Base class for protocol classes.
Protocol classes are defined as::
class Proto(Protocol): def meth(self) -> int: ...Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing).
For example::
class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type checkSee PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as::
class GenProto(Protocol[T]): def meth(self) -> T: ...Ancestors
- typing.Protocol
- typing.Generic
Methods
async def sync_reporting_receipts(self, request: SyncReportingReceiptsRequest) ‑> TaskResult[SyncReportingReceiptsResponse]-
Expand source code
async def sync_reporting_receipts( self, request: SyncReportingReceiptsRequest ) -> TaskResult[SyncReportingReceiptsResponse]: ...
class ReportingSubmissionAuthorizer (*args, **kwargs)-
Expand source code
class ReportingSubmissionAuthorizer(Protocol): """Trusted application adapter resolving the exact client's current access. Resolve seller identity from trusted client/registry configuration, account from an authorized seller account lookup, and consumer from authenticated credentials/registry. Never source these identities from receipt payloads, an asserted account reference, or a debug/raw response. Aliases must already be resolved. Raise on revoked access or an identity disagreement. Called before any store read/reservation, before each send, and before returning completed cached outcomes. It must authorize replay afresh too. """ async def __call__( self, client: ReportingReceiptSubmissionClient ) -> ReportingSubmissionScope: ...Trusted application adapter resolving the exact client's current access.
Resolve seller identity from trusted client/registry configuration, account from an authorized seller account lookup, and consumer from authenticated credentials/registry. Never source these identities from receipt payloads, an asserted account reference, or a debug/raw response. Aliases must already be resolved. Raise on revoked access or an identity disagreement.
Called before any store read/reservation, before each send, and before returning completed cached outcomes. It must authorize replay afresh too.
Ancestors
- typing.Protocol
- typing.Generic