Skip to content

feat: flatten challenge builders to kwargs; delete *Input + *Config wrappers - #32

Merged
vvillait88 merged 1 commit into
mainfrom
feat/303a-challenge-flatten
May 14, 2026
Merged

feat: flatten challenge builders to kwargs; delete *Input + *Config wrappers#32
vvillait88 merged 1 commit into
mainfrom
feat/303a-challenge-flatten

Conversation

@vvillait88

Copy link
Copy Markdown
Contributor

Summary

Drops the verbose (BuildXInput(...)) wrapper construction across the agentscore_commerce.challenge submodule in favor of plain **kwargs. Same call shape Node already uses — Python's just been ceremonially verbose because TypeScript interfaces satisfy as object literals while Python needed a dataclass wrapper.

This is a breaking change: callers that build BuildXInput(...) objects need to pass kwargs directly instead. Pure mechanical migration at every call site. Internal-only consumers (store + martin) update in lockstep on the same release train; no deprecation horizon.

Builders flattened

Before After
respond_402(Respond402Input(...)) respond_402(*, mppx_challenge_headers, body, x402=None)
build_402_body(Build402BodyInput(...)) build_402_body(*, accepted_methods, agent_instructions=None, identity_metadata=None, ...)
build_accepted_methods(BuildAcceptedMethodsInput(tempo=TempoConfig(...), ...)) build_accepted_methods(*, tempo=None, x402_base=None, solana_mpp=None, stripe=None) — each value a plain dict; per-rail defaults applied inline
build_how_to_pay(BuildHowToPayInput(rails=HowToPayRails(...))) build_how_to_pay(*, url, retry_body_json, total_usd, rails: dict[str, dict], ...)
build_agent_instructions(BuildAgentInstructionsInput(...)) build_agent_instructions(*, how_to_pay, compatible_clients=None, extra_warnings=None, ...)
build_validation_error(BuildValidationErrorInput(...)) build_validation_error(*, code, message, next_steps=None, ...)example_body uses a sentinel so omitted kwarg suppresses the field, =None emits a literal null
build_identity_metadata(IdentityMetadataInput(...)) build_identity_metadata(*, mode, wallet=None, ...)

Deleted from public exports

Build402BodyInput, BuildAcceptedMethodsInput, BuildAgentInstructionsInput, BuildHowToPayInput, BuildValidationErrorInput, IdentityMetadataInput, Respond402Input, TempoConfig, X402BaseConfig, SolanaMppConfig, StripeConfig, TempoRailConfig, X402BaseRailConfig, SolanaMppRailConfig, StripeRailConfig, HowToPayRails.

Kept (consumers pattern-match on these)

Respond402Result, SignerMatchResult, X402PaymentRequired, IdentityMode, AgentMemoryHint, PricingBlock, OrderReceipt + shipping/product subtypes.

Test plan

  • uv run pytest tests/ — 1031 passed / 3 skipped, 95.12% coverage
  • uv run ty check agentscore_commerce/ — clean
  • uv run ruff check . && uv run ruff format . — clean
  • examples/multi_rail_merchant.py migrated to the kwargs shape; ~30-line reduction
  • One follow-up bridge: respond_402 accepts x402 as a dict at the public boundary, constructs PaymentRequiredHeaderInput internally pending the wwwauthenticate-side flatten in a separate PR. Public-API-flat already.

Drops the verbose `(BuildXInput(...))` wrapper construction across the
challenge submodule in favor of plain `**kwargs`. Breaking surface change
for callers that pass *Input dataclasses; pure kwargs replacement at the
call site. Internal-only consumers update in lockstep on the same release
train, no deprecation horizon.

Builders flattened:
- build_402_body
- build_accepted_methods (per-rail args are plain dicts;
  recipient + per-rail defaults apply inline)
- build_agent_instructions
- build_how_to_pay (`rails` is a flat `dict[str, dict]` keyed by rail name)
- respond_402 (`x402` arg accepts a dict; internal adapter still constructs
  PaymentRequiredHeaderInput pending the wwwauthenticate flatten in a
  subsequent PR — invisible to callers)
- build_validation_error (example_body uses a sentinel so an explicit None
  emits a literal null while an omitted kwarg suppresses the field)
- build_identity_metadata

Deleted from public exports:
- Build402BodyInput, BuildAcceptedMethodsInput, BuildAgentInstructionsInput,
  BuildHowToPayInput, BuildValidationErrorInput, IdentityMetadataInput,
  Respond402Input
- TempoConfig, X402BaseConfig, SolanaMppConfig, StripeConfig (accepted_methods)
- TempoRailConfig, X402BaseRailConfig, SolanaMppRailConfig, StripeRailConfig,
  HowToPayRails (how_to_pay)

Kept (consumers pattern-match on these): Respond402Result, SignerMatchResult,
X402PaymentRequired, IdentityMode.

Tests: 1031 passed / 3 skipped, 95.12% coverage. ty + ruff clean.
examples/multi_rail_merchant.py migrated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vvillait88
vvillait88 merged commit 68a9828 into main May 14, 2026
7 checks passed
@vvillait88
vvillait88 deleted the feat/303a-challenge-flatten branch May 14, 2026 18:15
vvillait88 added a commit that referenced this pull request May 14, 2026
## Summary

Drops the wrapper construction for the three x402 helpers. Same pattern
as the challenge flatten in #32: same call shape Node already uses,
internal-only consumers update in lockstep.

| Before | After |
|---|---|
|
`validate_x402_network_config(ValidateX402NetworkConfigInput(base_network=X))`
| `validate_x402_network_config(base_network=X)` |
| `verify_x402_request(VerifyX402RequestInput(headers=...,
is_cached_address=..., accepted_network=...))` |
`verify_x402_request(headers=..., is_cached_address=...,
accepted_network=...)` |
| `process_x402_settle(ProcessX402SettleInput(x402_server=...,
payload=..., resource_config=..., resource_meta=..., extension=...,
transport_context=...))` | `process_x402_settle(x402_server=...,
payload=..., resource_config=..., resource_meta=..., extension=...,
transport_context=...)` |

## Deleted from exports

`ProcessX402SettleInput`, `VerifyX402RequestInput`,
`ValidateX402NetworkConfigInput`.

## Kept

Result/failure dataclasses + tagged-error type (consumers
pattern-match): `ProcessX402SettleSuccess`, `ProcessX402SettleFailure`,
`ProcessX402SettleResult`, `VerifyX402RequestSuccess`,
`VerifyX402RequestFailure`, `VerifyX402RequestResult`,
`ClassifiedX402Error`.

## Test plan

- [x] `uv run pytest tests/` — 1031 passed / 3 skipped, 95.10% coverage
- [x] `uv run ty check agentscore_commerce/` — clean
- [x] `uv run ruff check . && uv run ruff format .` — clean
- [x] `examples/multi_rail_merchant.py` migrated

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
vvillait88 added a commit that referenced this pull request May 14, 2026
…gs (#34)

## Summary

Drops the wrapper construction for the 5 payment-side builders in
`directive.py`, `headers.py`, and `settlement_override.py`. Same pattern
as #32 + #33.

## Builders flattened

| Before | After |
|---|---|
| `build_payment_request_blob(PaymentRequestInput(...))` |
`build_payment_request_blob(*, amount_usd, rail=None, ...)` |
| `payment_directive(PaymentDirectiveInput(...))` |
`payment_directive(*, id, realm, request, rail=None, ...)` |
| `build_payment_directive(BuildPaymentDirectiveInput(...))` |
`build_payment_directive(*, rail, id, realm, amount_usd, ...)` |
| `build_payment_headers(BuildPaymentHeadersInput(...))` |
`build_payment_headers(*, rails=None, order_id="", realm="", x402=None)`
|
| `settlement_override_header(SettlementOverrides(amount=X))` |
`settlement_override_header(*, amount=X)` |

## Deleted from exports

`PaymentRequestInput`, `PaymentDirectiveInput`,
`BuildPaymentDirectiveInput`, `BuildPaymentHeadersInput`,
`SettlementOverrides`.

## Kept (data shapes consumers construct)

`PaymentHeadersRail`, `PaymentHeadersResult`, `X402AcceptsBlock`.

## Test plan

- [x] `uv run pytest tests/` — 1031 passed / 3 skipped, 95.05% coverage
- [x] `uv run ty check agentscore_commerce/` — clean
- [x] `uv run ruff check . && uv run ruff format .` — clean
- [x] Migrated callers:
`tests/test_payment_{directive,headers,misc}.py`,
`examples/api_provider.py`, `examples/variable_cost_merchant.py`,
`agentscore_commerce/discovery/probe.py`

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
vvillait88 added a commit that referenced this pull request May 14, 2026
…edHeaderInput (#36)

## Summary

Drops the wrapper for `payment_required_header` — the x402
PAYMENT-REQUIRED header builder.

| Before | After |
|---|---|
| `payment_required_header(PaymentRequiredHeaderInput(x402_version=...,
accepts=..., resource=...))` | `payment_required_header(*, x402_version,
accepts, resource=None)` |

Also drops the wrapper-bridge `respond_402` carried since #32 — its
public `x402: dict` kwarg now flows straight to
`payment_required_header(**x402)` without re-wrapping.

## Internal callers updated

- `challenge/respond_402.py`
- `payment/headers.py` (`build_payment_headers` x402 branch)
- `discovery/probe.py` (discovery probe PAYMENT-REQUIRED header)

## Deleted from exports

`PaymentRequiredHeaderInput`.

## Test plan

- [x] `uv run pytest tests/` — 1031 passed / 3 skipped, 95.04% coverage
- [x] `uv run ty check agentscore_commerce/` — clean
- [x] `uv run ruff check . && uv run ruff format .` — clean
- [x] `uv run vulture agentscore_commerce/ --min-confidence 80` — only
the known string-cast / Protocol-param false positives remain (unchanged
from main)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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